编辑访问控制练习 - java
Edited Access control exercise - java
我需要通过在 class Terminal
中创建 public hackCar
方法来打印 TestCar
class 的属性。 hackCar
方法需要传入一个TestCar
作为参数,打印TestCar
的属性。此作业的警告是我不能触摸 TestCar
class 中的任何内容。
我仍在努力打印 TestCar
中的两个 private
属性。如何使用 TestCar
对象作为 hackCar
方法中的参数从 TestCar
class 打印两个 private
属性?
故事 class:
class Story {
public static void main(String args[]) {
TestCar testCar = new TestCar();
Terminal terminal = new Terminal();
terminal.hackCar(testCar);
}
}
class Terminal {
public void hackCar(TestCar other) {
System.out.println(other.doorUnlockCode);
System.out.println(other.hasAirCondition);
System.out.println(other.brand);
System.out.println(other.licensePlate);
}
}
class TestCar {
private int doorUnlockCode = 602413;
protected boolean hasAirCondition = false;
String brand = "TurboCarCompany";
public String licensePlate = "PHP-600";
}
谢谢!
您无法访问 class 之外的对象的私有属性。这就是 Encapsulation
在 OOP
中的意义所在。如果 class 的属性必须可以从 class 外部访问,则它们不能是私有的。或者您应该为它们提供一些访问器方法。我认为这就是 Java Beans
在 java 框架中如此受欢迎的原因。
您也可以使用 Reflection
访问 java 中 class 的私有属性,但我认为这不是您要找的。
因为你不能接触 class TestCar,你不能设置任何 Getter 方法从 class 外部访问 class 的私有成员=].
所以,唯一的方法(在不使用任何 Getter 函数的情况下访问 class 的私有成员)是在 [=44] 中使用反射 API =].
这是代码,
public void hackCar(TestCar other) {
Field f = other.getDeclaredField("doorUnlockCode"); /*here we create the object of the desired field*/
f.setAccessible(true); //here, we set its access to true
System.out.println(f.get(obj)); /*here, we use the field object to get its value*/
Field f1 = other.getDeclaredField("hasAirCondition");
f1.setAccessible(true);
System.out.println(f1.get(obj));
Field f2 = other.getDeclaredField("brand");
f2.setAccessible(true);
System.out.println(f2.get(obj));
System.out.println(other.licensePlate); /*this can be accessed directly since the access specifier for the field is "public"*/
}
你可以这样修改你的HackCar方法。
您需要导入这些。
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
这是解决上述问题的方法,但也有其自身的缺陷。它会导致性能开销,还会导致安全问题,因为它违反了的抽象原则]OOP.
因此,请明智地使用此解决方案。
注意 - 您还可以通过定义 class 来访问具有访问说明符 protected 或 default 的字段(我们称它为 C)与 TestCar class 在同一个包中,并使用 class C 的成员函数作为 protected[=] 的 getter 函数36=] 和 默认 TestCar 字段 class.
您提到了三个 classes:Story
、Terminal
、TestCar
。在您的问题中,所有这些都被定义为私有包(默认可见性)——也许是为了简单起见。但是 TestCar
被定义 public
and/or Story
/ Terminal
驻留在同一个包中。只有这样 TestCar
才能在 Story
和 Terminal
.
内解决
如果 classes 都在一个包中,则可以立即访问 TestCar
的 hasAirCondition
、brand
和 licensePlate
字段在 Terminal.hackCar(...)
。因此,这种访问无需反射即可实现。
如果 TestCar
被定义 public
并且在包 lib.cars
中,但是 Story
和 Terminal
在项目的包 app.cars
中,那么class Accessor
在包 lib.cars
中定义的项目可以提供对包可见字段 hasAirCondition
和 brand
:
的访问
package lib.cars;
public class Accessor {
public static boolean hasAirCondition(TestCar testCar) {
return testCar.hasAirCondition;
}
public static String getBrand(TestCar testCar) {
return testCar.brand;
}
}
因此您仍然可以访问 TestCar
.
四个字段中的三个
如果没有反射,private
字段将始终无法访问。由于其他答案都在解释如何使用反射访问 TestCar
的字段,因此我不会重复。因此,我的回答是对其他答案的补充。
但如其他答案所述,使用反射有其缺点 - 即重构,例如将字段 doorUnlockCode
简单重命名为 doorsUnlockCode
。因此,也许人们应该尽可能长时间地使用常规方式,并将反射作为最后的手段。
我们可以将这两种方式合并到 Accessor
class:
package lib.cars;
import java.lang.reflect.Field;
public class Accessor {
public static boolean hasAirCondition(TestCar testCar) {
return testCar.hasAirCondition;
}
public static String getBrand(TestCar testCar) {
return testCar.brand;
}
public static int getDoorUnlockCode(TestCar testCar) throws Exception {
Field field = TestCar.class.getDeclaredField("doorUnlockCode");
field.setAccessible(true);
field.setAccessible(true);
return (int) field.get(testCar);
}
}
在Terminal
中使用如下:
public class Terminal {
public void hackCar(TestCar other) throws Exception {
System.out.println(Accessor.getDoorUnlockCode(other));
System.out.println(Accessor.hasAirCondition(other));
System.out.println(Accessor.getBrand(other));
System.out.println(other.licensePlate);
}
}
我需要通过在 class Terminal
中创建 public hackCar
方法来打印 TestCar
class 的属性。 hackCar
方法需要传入一个TestCar
作为参数,打印TestCar
的属性。此作业的警告是我不能触摸 TestCar
class 中的任何内容。
我仍在努力打印 TestCar
中的两个 private
属性。如何使用 TestCar
对象作为 hackCar
方法中的参数从 TestCar
class 打印两个 private
属性?
故事 class:
class Story {
public static void main(String args[]) {
TestCar testCar = new TestCar();
Terminal terminal = new Terminal();
terminal.hackCar(testCar);
}
}
class Terminal {
public void hackCar(TestCar other) {
System.out.println(other.doorUnlockCode);
System.out.println(other.hasAirCondition);
System.out.println(other.brand);
System.out.println(other.licensePlate);
}
}
class TestCar {
private int doorUnlockCode = 602413;
protected boolean hasAirCondition = false;
String brand = "TurboCarCompany";
public String licensePlate = "PHP-600";
}
谢谢!
您无法访问 class 之外的对象的私有属性。这就是 Encapsulation
在 OOP
中的意义所在。如果 class 的属性必须可以从 class 外部访问,则它们不能是私有的。或者您应该为它们提供一些访问器方法。我认为这就是 Java Beans
在 java 框架中如此受欢迎的原因。
您也可以使用 Reflection
访问 java 中 class 的私有属性,但我认为这不是您要找的。
因为你不能接触 class TestCar,你不能设置任何 Getter 方法从 class 外部访问 class 的私有成员=].
所以,唯一的方法(在不使用任何 Getter 函数的情况下访问 class 的私有成员)是在 [=44] 中使用反射 API =].
这是代码,
public void hackCar(TestCar other) {
Field f = other.getDeclaredField("doorUnlockCode"); /*here we create the object of the desired field*/
f.setAccessible(true); //here, we set its access to true
System.out.println(f.get(obj)); /*here, we use the field object to get its value*/
Field f1 = other.getDeclaredField("hasAirCondition");
f1.setAccessible(true);
System.out.println(f1.get(obj));
Field f2 = other.getDeclaredField("brand");
f2.setAccessible(true);
System.out.println(f2.get(obj));
System.out.println(other.licensePlate); /*this can be accessed directly since the access specifier for the field is "public"*/
}
你可以这样修改你的HackCar方法。
您需要导入这些。
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
这是解决上述问题的方法,但也有其自身的缺陷。它会导致性能开销,还会导致安全问题,因为它违反了的抽象原则]OOP.
因此,请明智地使用此解决方案。
注意 - 您还可以通过定义 class 来访问具有访问说明符 protected 或 default 的字段(我们称它为 C)与 TestCar class 在同一个包中,并使用 class C 的成员函数作为 protected[=] 的 getter 函数36=] 和 默认 TestCar 字段 class.
您提到了三个 classes:Story
、Terminal
、TestCar
。在您的问题中,所有这些都被定义为私有包(默认可见性)——也许是为了简单起见。但是 TestCar
被定义 public
and/or Story
/ Terminal
驻留在同一个包中。只有这样 TestCar
才能在 Story
和 Terminal
.
如果 classes 都在一个包中,则可以立即访问 TestCar
的 hasAirCondition
、brand
和 licensePlate
字段在 Terminal.hackCar(...)
。因此,这种访问无需反射即可实现。
如果 TestCar
被定义 public
并且在包 lib.cars
中,但是 Story
和 Terminal
在项目的包 app.cars
中,那么class Accessor
在包 lib.cars
中定义的项目可以提供对包可见字段 hasAirCondition
和 brand
:
package lib.cars;
public class Accessor {
public static boolean hasAirCondition(TestCar testCar) {
return testCar.hasAirCondition;
}
public static String getBrand(TestCar testCar) {
return testCar.brand;
}
}
因此您仍然可以访问 TestCar
.
如果没有反射,private
字段将始终无法访问。由于其他答案都在解释如何使用反射访问 TestCar
的字段,因此我不会重复。因此,我的回答是对其他答案的补充。
但如其他答案所述,使用反射有其缺点 - 即重构,例如将字段 doorUnlockCode
简单重命名为 doorsUnlockCode
。因此,也许人们应该尽可能长时间地使用常规方式,并将反射作为最后的手段。
我们可以将这两种方式合并到 Accessor
class:
package lib.cars;
import java.lang.reflect.Field;
public class Accessor {
public static boolean hasAirCondition(TestCar testCar) {
return testCar.hasAirCondition;
}
public static String getBrand(TestCar testCar) {
return testCar.brand;
}
public static int getDoorUnlockCode(TestCar testCar) throws Exception {
Field field = TestCar.class.getDeclaredField("doorUnlockCode");
field.setAccessible(true);
field.setAccessible(true);
return (int) field.get(testCar);
}
}
在Terminal
中使用如下:
public class Terminal {
public void hackCar(TestCar other) throws Exception {
System.out.println(Accessor.getDoorUnlockCode(other));
System.out.println(Accessor.hasAirCondition(other));
System.out.println(Accessor.getBrand(other));
System.out.println(other.licensePlate);
}
}