C’est une question qui m’a été posée lors d’une interview: j’ai la classe A avec des membres privés et la classe B étend la classe A. Je sais que les membres privés d’une classe ne sont pas accessibles, mais la question est: j’ai besoin d’accéder aux membres privés de la classe A à partir de classe B, plutôt que de créer des variables avec la même valeur en classe B.
L'intervieweur testait vos connaissances sur les modificateurs d'accès ou votre approche pour modifier les classes existantes, ou les deux.
Je les aurais énumérés (public, privé, protégé, paquet privé) avec une explication de chacun. Nous avons ensuite ajouté que la classe A devrait être modifiée pour permettre l'accès aux membres de la classe B, soit en ajoutant des setters et des accesseurs, soit en modifiant les modificateurs d'accès des membres. Ou la classe B pourrait utiliser la réflexion. Enfin, discutez des avantages et des inconvénients de chaque approche.
Réflexion? En omettant les importations, cela devrait fonctionner:
public class A {
private int ii = 23;
}
public class B extends A {
private void readPrivateSuperClassField() throws Exception {
Class<?> clazz = getClass().getSuperclass();
Field field = clazz.getDeclaredField("ii");
field.setAccessible(true);
System.out.println(field.getInt(this));
}
public static void main(String[] args) throws Exception {
new B().readPrivateSuperClassField();
}
}
Cela ne fonctionnera pas si vous faites quelque chose comme ça avant l'invocation readPrivateSuperClassField();
:
System.setSecurityManager(new SecurityManager() {
@Override
public void checkMemberAccess(Class<?> clazz, int which) {
if (clazz.equals(A.class)) {
throw new SecurityException();
} else {
super.checkMemberAccess(clazz, which);
}
}
});
Et il existe d'autres conditions dans lesquelles l'approche par réflexion ne fonctionnera pas. Voir les documents de l'API pour SecurityManager et AccessibleObject pour plus d'informations. Merci à CPerkins de l'avoir signalé.
J'espère qu'ils testaient simplement vos connaissances et ne cherchaient pas une application réelle de ce genre de choses ;-) Bien que je pense qu'un hack laid comme celui-ci peut être légitime dans certains cas Edge.
En utilisant des accesseurs publics (getters & setters) des membres privés de A ...
L'architecture est cassée. Les membres privés sont privés parce que vous ne voulez pas qu'ils soient consultés en dehors de la classe et des amis.
Vous pouvez utiliser des hacks d'amis, des accesseurs, promouvoir le membre ou #define private public
(heh). Mais ce sont toutes des solutions à court terme - vous devrez probablement revoir l'architecture brisée à un moment donné.
Vous ne pouvez pas accéder aux membres privés de la classe parent. Vous l'avez rendu protégé ou avez une méthode protégée/publique qui y a accès.
EDIT: Il est vrai que vous pouvez utiliser la réflexion. Mais ce n'est pas habituel et ce n'est pas une bonne idée de casser l'encapsulation.
Une classe imbriquée peut accéder à tous les membres privés de sa classe englobante (champs et méthodes). Par conséquent, une classe imbriquée publique ou protégée héritée d'une sous-classe a un accès indirect à tous les membres privés de la superclasse.
public class SuperClass
{
private int a = 10;
public void makeInner()
{
SubClass in = new SubClass();
in.inner();
}
class SubClass
{
public void inner()
{
System.out.println("Super a is " + a);
}
}
public static void main(String[] args)
{
SuperClass.SubClass s = new SuperClass().new SubClass();
s.inner();
}
}
De JLS §8.3. Déclarations de terrain :
Un champ privé d'une superclasse peut être accessible à une sous-classe - par exemple, si les deux classes sont membres de la même classe. Néanmoins, un champ privé n'est jamais hérité par une sous-classe.
J'écris l'exemple de code:
public class Outer
{
class InnerA
{
private String text;
}
class InnerB extends InnerA
{
public void setText(String text)
{
InnerA innerA = this;
innerA.text = text;
}
public String getText()
{
return ((InnerA) this).text;
}
}
public static void main(String[] args)
{
final InnerB innerB = new Outer().new InnerB();
innerB.setText("hello world");
System.out.println(innerB.getText());
}
}
L'explication de l'accessibilité de InnerA.text
se trouve ici JLS §6.6.1. Détermination de l'accessibilité :
Sinon, le membre ou le constructeur est déclaré privé et l'accès est autorisé si, et seulement si, il se produit dans le corps de la classe de niveau supérieur (§7.6) qui inclut la déclaration du membre ou du constructeur.
En utilisant des setters et des geters, vous pouvez y accéder
Si je comprends bien la question, vous pouvez changer private
en protected
. Les variables protégées sont accessibles aux sous-classes mais se comportent autrement comme des variables privées.
class A
{
private int a;
void setA(int a)
{
this.a=a;
}
int getA()
{
return a;
}
}
Class B extends A
{
public static void main(String[] arg)
{
B obj= new B();
obj.setA(10);
System.out.println("The value of A is:"+obj.getA());
}
}
Vous pouvez utiliser les setters et les getters de la classe A. Ce qui donne la même impression que si vous utilisiez un objet de la classe A.
Avez-vous pensé à les rendre protégés ? Juste pour vous assurer que vous êtes au courant de cette option, si vous êtes alors excusez-moi d’avoir soulevé cette anecdote;)
Vous trouverez ci-dessous un exemple d'accès aux membres privés de la superclasse dans l'objet de la sous-classe.
J'utilise des constructeurs pour faire la même chose.
Ci-dessous, la superclasse Fruit
public class Fruit {
private String type;
public Fruit() {
}
public Fruit(String type) {
super();
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Ci-dessous la sous-classe Goyave héritant de Fruit
public class Guava extends Fruit{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Guava(String name,String type) {
super(type);
this.name=name;
}
}
Ci-dessous, la fonction principale dans laquelle nous créons un objet de sous-classe et affichant également le membre de superclasse.
public class Main {
public static void main(String[] args) {
Guava G1=new Guava("kanpuria", "red");
System.out.println(G1.getName()+" "+G1.getType());
}
}
De toute évidence, la technique préférée est de les protéger ou d’ajouter des setters/getters. La réflexion est une option de désespoir.
Juste pour montrer à l'intervieweur, si "accès" signifie un accès en lecture, et si la classe A génère XML ou JSON, etc., vous pouvez sérialiser A et analyser les champs intéressants.
Vous voudrez peut-être le changer en protégé. Veuillez référer cette
https://docs.Oracle.com/javase/tutorial/Java/javaOO/accesscontrol.html
Si c'est quelque chose que vous devez faire à tout prix juste pour le plaisir de le faire, vous pouvez utiliser la réflexion. Il vous donnera la liste de toutes les variables définies dans la classe, qu'elles soient publiques, privées ou protégées. Ceci a sûrement ses frais généraux mais oui, c'est quelque chose qui vous permettra d'utiliser des variables privées. Avec cela, vous pouvez l'utiliser dans n'importe quelle classe. Il ne doit pas nécessairement s'agir d'une sous-classe. Veuillez vous reporter à l'exemple ci-dessous. Cela peut avoir quelques problèmes de compilation mais vous pouvez avoir l’idée de base et ça marche
private void getPropertiesFromPrivateClass(){
Field[] privateVariablesArray = PrivateClassName.getClass().getDeclaredFields();
Set<String> propertySet = new HashSet<String>();
Object propertyValue;
if(privateVariablesArray.length >0){
for(Field propertyVariable :privateVariablesArray){
try {
if (propertyVariable.getType() == String.class){
propertyVariable.setAccessible(true);
propertyValue = propertyVariable.get(envtHelper);
System.out.println("propertyValue");
}
} catch (IllegalArgumentException illegalArgumentException) {
illegalArgumentException.printStackTrace();
} catch (IllegalAccessException illegalAccessException) {
illegalAccessException.printStackTrace();
}
}
J'espère que cela vous sera utile. Bonne apprentissage :)
Façons d'accéder aux membres privés de la superclasse dans la sous-classe:
Vous pouvez également utiliser une classe interne, par exemple
public class PrivateInnerClassAccess {
private int value=20;
class InnerClass {
public void accessPrivateFields() {
System.out.println("Value of private field : " + value);
}
}
public static void main(String arr[])
{
PrivateInnerClassAccess access = new PrivateInnerClassAccess();
PrivateInnerClassAccess.InnerClass innerClass = access.new InnerClass();
innerClass.accessPrivateFields();
}
}
4 .Vous pouvez également utiliser Reflection, par exemple
public class A {
private int value;
public A(int value)
{
this.value = value;
}
}
public class B {
public void accessPrivateA()throws Exception
{
A a = new A(10);
Field privateFields = A.class.getDeclaredField("value");
privateFields.setAccessible(true);
Integer value = (Integer)privateFields.get(a);
System.out.println("Value of private field is :"+value);
}
public static void main(String arr[]) throws Exception
{
B b = new B();
b.accessPrivateA();
}
}
En utilisant la méthode setter, vous pouvez utiliser else avec l'aide de refection, vous pouvez utiliser un membre privé de la classe en définissant ce membre en disant a - take a from class et en définissant a.setAccessible (true);
Nous ne pouvons pas y accéder directement. mais en utilisant Setter et Getter nous pouvons accéder,
Le code est:
class AccessPrivate1 {
private int a=10; //private integer
private int b=15;
int getValueofA()
{
return this.a;
}
int getValueofB()
{
return this.b;
}
}
public class AccessPrivate{
public static void main(String args[])
{
AccessPrivate1 obj=new AccessPrivate1();
System.out.println(obj.getValueofA()); //getting the value of private integer of class AccessPrivate1
System.out.println(obj.getValueofB()); //getting the value of private integer of class AccessPrivate1
}
}
Vous pouvez utiliser Accesseurs (méthode getter et setter) dans votre code.
Un membre privé est accessible dans la sous-classe de sorte que vous ne pouvez pas modifier la variable, mais vous pouvez accéder à la variable en lecture seule.
Vous ne pouvez pas accéder directement aux variables privées d'une classe de l'extérieur directement.
Vous pouvez accéder au membre privé en utilisant getter et setter .
Private sera caché jusqu'à ce que vous ayez le droit d'y accéder. Par exemple, Getters ou setters du programmeur qui a écrit le parent. S'ils ne sont pas visibles non plus, alors acceptez le fait qu'ils sont simplement privés et inaccessibles. Pourquoi exactement tu veux faire ça ??
Class A
{
private int i;
int getValue()
{
return i;
}
}
class B extends A
{
void getvalue2()
{
A a1= new A();
sop(a1.getValue());
}
}
Je ne connais pas Java, mais dans certaines langues, imbriqué types peut le faire:
class A {
private string someField;
class B : A {
void Foo() {
someField = "abc";
}
}
}
Sinon, utilisez une méthode d'accès ou un champ protected
(bien qu'ils soient souvent maltraités).
Pour accéder aux variables privées de la classe parente de la sous-classe, vous pouvez utiliser protected ou ajouter des getters et des setters aux variables privées de la classe parente.