我有一个Circle类类型的对象,我有一个成员'r'来存储半径。 现在因为我经常使用这些对象,所以我不想将半径设为私有,因为其他类必须使用getR()方法,这会使代码难以阅读。 例如,读取这样的代码要容易得多: double alpha = b1.r + b2.r -2 * b1.r * b2.r; 而不是读这个: double alpha = b1.getR()+ b2.getR() - 2 * b1.getR()* b2.getR();
然而,因为这是一个半径,它的正方形也被大量使用,我想计算一次,我想有一个半径的设定器,所以我可以同时更新r和它的方块。 所以我希望r是私有的,强制使用setR(),但我想要它的publc,所以它可以被引用进行阅读。 有没有人知道在Java中这样做的方法?
答案 0 :(得分:4)
Java没有只读属性的概念。
如果您允许r可读,则有人可以并且将随机更改它。此外,进入是一个坏习惯。只是不要。远景的例子是:如果你需要这个在一些奇怪的非欧几里德空间中运作怎么办?现在你无论如何都要去解决这个问题。
现实选择:
你可以偏离规范并将你的getter命名为r()。几乎一样短。
或者,你可以将这样的数学推入圆类,它可以直接引用它的成员。使用较短的名称可以获得更好的封装效果。
class Circle() {
static double alpha(Circle c1, Circle c2) {
return c1.r + c2.r -2*c1.r*c2.r
}
...
}
答案 1 :(得分:1)
A)。不要跳过使用getter和setter来为代码提供封装。
B)。如果可读性是你的问题,那么我建议使用getR()方法获取半径并存储在局部变量中。 例如 - int firstCircleRadius = first.getR()和其他圆圈类似,并使用局部变量使公式易于阅读。
C)。不要将r用作属性名称。使用半径而不是增加可读性。
答案 2 :(得分:0)
我个人会使用getter和setter。但是,您可以将实际半径存储在私有成员中,然后使用setR()
方法更新虚拟半径r
。这并不能解决手动更改r
的问题。
private int radius;
public int r;
public void setR(int r) {
radius = r;
square(); //do you squaring and other math
this.r = r;
}
答案 3 :(得分:0)
我最近被这个问题烧了,冒着得到一堆负面投票和Java社区愤怒的风险,我建议不要依赖Java访问 - 没有关于类变量或者方法(或者我曾经认为“私有”用于在面向对象的编程语言中进行封装。只需使用public来处理所有事情并在晚上睡得好。这是一个解释,请考虑以下类:
package hiddenscope;
public class Privacy {
private int privateInt = 12;
private double oneBy2pi = 0.5 / Math.PI;
private String myClassName;
public Privacy () {
privateInt = 12;
myClassName = this.getClass().getName();
print ("Constructor");
}
// Given the circumference of a circle, get its radius
public double c2r (double c) {
return c * oneBy2pi;
}
// Do not let any other class call this method
private void print (String caller) {
System.out.println ("["+caller+"] Current value of privateInt in class " +
myClassName + " is " + privateInt);
}
}
这是一个更改上述类的私有变量privateInt的类,并将其称为私有“print”方法,即使是从包外部(受保护的,任何人?):
package userpackage;
import hiddenscope.Privacy;
import java.lang.reflect.*;
public class EditPrivate {
private int i2set;
private String fieldNameToModify, myClassName;
private Object p;
private Method printer;
public EditPrivate (Object object, String fName, int value) {
fieldNameToModify = fName;
i2set = value;
p = object;
myClassName = this.getClass().getName();
Method[] methods = p.getClass().getDeclaredMethods();
for (Method m : methods) {
if (m.getName().equals("print")) {
printer = m;
printer.setAccessible(true);
break;
}}
if (printer == null)
return;
try {
printer.invoke (p, myClassName);
} catch (IllegalAccessException ex1) { ex1.printStackTrace();
} catch (InvocationTargetException ex2) { ex2.printStackTrace();
}}
public void invadePrivacy () throws Exception {
Field[] fields = p.getClass().getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
if (fieldName.equals(fieldNameToModify)) {
field.setAccessible(true);
if ("int".equals(field.getType().toString())) {
try {
field.setInt(p, i2set);
if (printer != null)
printer.invoke (p, myClassName);
return;
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}}}}
throw new Exception ("No such int field: " + fieldNameToModify);
}
public static void main(String[] args) {
try {
Privacy p = new Privacy();
new EditPrivate(p, "privateInt", 15).invadePrivacy();
} catch (Exception ex) {
ex.printStackTrace();
}}}
为了增加对这种伤害的侮辱,这就是多线程弄乱一个类的内部和私有变量(oneBy2pi应该是私有的!)
package userpackage;
import java.lang.reflect.Field;
import java.util.concurrent.*;
import java.util.*;
import hiddenscope.*;
public class ThreadedPi implements Runnable {
Privacy p = new Privacy();
private int nSample = 2000, bins[] = new int[4]; // 94814117 999065 0003379, 2028859
private Field c2dField;
private boolean mutate;
public ThreadedPi () {
Field[] fields = p.getClass().getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
if (fieldName.equals("oneBy2pi")) {
field.setAccessible(true);
c2dField = field;
}}}
synchronized private boolean setMutationOfField (boolean master, boolean value) {
if (master)
mutate = value;
return mutate;
}
public void run () {
Random rng = new Random();
for ( ; ; ) {
if (setMutationOfField (false, true)) {
int nDigit = 2 + rng.nextInt(4);
double doublePi = 4.0 * Math.atan(1.0),
decimal = Math.pow(10, nDigit),
apprxPi = Math.round(decimal * doublePi) / decimal;
try {
c2dField.setDouble (p, 0.5/apprxPi);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}} else {
return;
}}}
public void execute () {
setMutationOfField (true, true);
new Thread (this).start();
Executed[] class2x = new Executed[nSample];
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0 ; i < 4 ; i++)
bins[i] = 0;
for (int i = 0 ; i < nSample ; i++) {
class2x[i] = new Executed();
executor.execute(class2x[i]);
double d = class2x[i].getDiameter(-1);
if (d < 399.99) bins[0]++;
else if (d < 400) bins[1]++;
else if (d < 400.01) bins[2]++;
else bins[3]++;
//System.out.println ("d: " + d);
}
setMutationOfField (true, false);
for (int i = 0 ; i < 4 ; i++)
System.out.print("\t\t[" + (i+1) + "] " + bins[i]);
System.out.println ();
}
public static void main(String[] args) {
ThreadedPi tp = new ThreadedPi();
for (int k = 0 ; k < 5 ; k++)
tp.execute();
}
private class Executed implements Runnable {
private double d=-1, c = 2513.274123;
synchronized double getDiameter (double setter) {
if (setter < 0) {
while (d < 0) {
try {
wait();
} catch (InterruptedException ex) {
}}} else {
d = setter;
notify();
}
return d;
}
public void run () {
getDiameter (p.c2d(c));
}}}
所有上述类都编译和运行完美,这解释了为什么“私有”在java中可能没有任何意义。盾牌,Scotty!