【问题标题】:How to access the private variables of a class in its subclass?如何访问其子类中的类的私有变量?
【发布时间】:2011-01-16 13:32:32
【问题描述】:

这是我在一次采访中被问到的一个问题:我有一个带有私有成员的类 A,而 B 类扩展了 A。我知道一个类的私有成员无法访问,但问题是:我需要访问一个类的私有成员从 B 类创建 A 类,而不是在 B 类中创建具有相同值的变量。

【问题讨论】:

  • 这个问题体现了一个矛盾的术语。如果私有成员应该是可访问的,那么它们不应该是私有的。如果它们应该是私有的,那么任何暴露它们的技术本质上都是不安全的,并且通常在生产代码中不应该被允许。你应该把问题转过来,问这是否是面试官环境中常见的问题,以及为什么。

标签: java core


【解决方案1】:

面试官要么测试你对访问修饰符的了解,要么测试你改变现有类的方法,或者两者兼而有之。

我会列出它们(公共的、私有的、受保护的、包私有的)以及每个的解释。然后继续说需要修改类 A 以允许从类 B 访问这些成员,方法是添加 setter 和 getter,或者通过更改成员的访问修饰符。或者 B 类可以使用反射。最后,谈谈每种方法的优缺点。

【讨论】:

  • 很好地解决了如何在面试情况下处理问题。
【解决方案2】:

反思?省略导入,这应该可以工作:

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();
    }

}

如果你在调用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);    
            }
        }
    });

还有其他情况下反射方法不起作用。有关更多信息,请参阅 the API docs for SecurityManagerAccessibleObject。感谢 CPerkins 指出这一点。

我希望他们只是测试你的知识,而不是寻找这些东西的真正应用;-) 虽然我认为像上面这样丑陋的 hack 在某些极端情况下可能是合法的。

【讨论】:

  • 罗伯特,只有在您的进程有权这样做时才有效。
  • 如果您不知道,或者(由于某种原因)无法获取字段名称(在本例中为ii)会发生什么情况?有什么解决方法吗?
【解决方案3】:

架构被破坏了。私有成员是私有的,因为您不希望他们在班级和朋友之外被访问。

您可以使用好友黑客、访问器、推广会员或#define private public(呵呵)。但这些都是短期解决方案——您可能不得不在某个阶段重新审视损坏的架构。

【讨论】:

  • 你是什么意思,“架构坏了”。他问的是一个测试他的 Java 知识的面试问题,而不是设计一个真实的系统。
  • 顺便说一句,如果你告诉他们他们的代码在面试中被破坏,这可能会帮助或阻碍你获得这份工作的机会。如果它有帮助,它可能是你会喜欢的工作。否则,你应该保持你的简历是最新的。
  • @Robert 架构被破坏了,因为您使用私有,因为这是正确的做法。如果这种情况发生变化,则表明您的设计需要更改。通过将私人提升为受保护来“修复”它就像只是告诉少数人您的 ATM PIN - 在很短的时间内可能没问题,但您应该更改它,或者获得一个联名帐户或其他东西。
  • 谢谢埃里克。我强烈建议你说的时候眨眼:-)
  • java LOL 中的预处理器指令!
【解决方案4】:

通过使用 A 的私有成员的公共访问器(getter 和 setter)...

【讨论】:

  • 你是 100% 正确的。但是告诉我一件事:如果 B 不继承 A 的任何私有字段,那么这些字段存储在哪里,因为我们可以使用 setter 设置它们?也许是一个愚蠢的问题,但这真的让我很困惑!
【解决方案5】:

您不能从父类访问私有成员。您已使其受保护或具有可以访问它们的受保护/公共方法。

EDIT:确实可以使用反射。但这并不常见,也不是打破封装的好主意。

【讨论】:

  • 不正确,你使用反射。
【解决方案6】:

嵌套类可以访问其封闭类的所有私有成员——包括字段和方法。因此,子类继承的公共或受保护的嵌套类可以间接访问超类的所有私有成员。

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();
    }
}

【讨论】:

    【解决方案7】:

    如果我对问题的理解正确,您可以将private 更改为protected。受保护的变量可以被子类访问,但在其他方面表现得像私有变量。

    【讨论】:

      【解决方案8】:

      通过使用 setter 和 getter,你可以访问它

      【讨论】:

        【解决方案9】:

        来自JLS §8.3. Field Declarations

        子类可能可以访问超类的私有字段 - 例如,如果两个类都是同一类的成员。然而,子类永远不会继承私有字段。

        我编写示例代码:

        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());
            }
        }
        

        InnerA.text的可访问性解释在这里JLS §6.6.1. Determining Accessibility

        否则,成员或构造函数被声明为私有,并且当且仅当它出现在包含成员或构造函数声明的顶级类(第 7.6 节)的主体内时才允许访问。

        【讨论】:

          【解决方案10】:

          您可以使用 A 类的 setter 和 getter。这给人的感觉就像您在使用 A 类的对象一样。

          【讨论】:

            【解决方案11】:

            您是否考虑过让它们受保护?只是为了确保你知道这个选项,如果你那么原谅我提出这个琐事;)

            【讨论】:

              【解决方案12】:
              • 派生类中不能访问私有成员
              • 如果你想访问意味着你可以使用getter和setter方法。
              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());
                } 
              }
              

              【讨论】:

                【解决方案13】:

                在您获得对它的正确访问权限之前,私人将被隐藏。例如由编写 Parent 的程序员编写的 Getter 或 setter。如果它们也不可见,那么请接受它们只是私有的并且您无法访问的事实。你到底为什么要这样做??

                【讨论】:

                  【解决方案14】:

                  我不了解 Java,但在某些语言中,嵌套类型可以做到这一点:

                      class A {
                          private string someField;
                          class B : A {
                              void Foo() {
                                  someField = "abc";
                              }
                          }
                      }
                  

                  否则,请使用访问器方法或 protected 字段(尽管它们经常被滥用)。

                  【讨论】:

                    【解决方案15】:

                    私有成员可以在子类中以一种您无法更改变量的方式访问,但您可以以只读方式访问该变量。

                    【讨论】:

                      【解决方案16】:

                      显然,使它们受到保护,或添加 setter/getter 是首选技术。反思是一种绝望的选择。

                      为了向面试官炫耀一下,IF“访问”就是读访问,如果A类生成XML或JSON等,你可以序列化A并解析感兴趣的字段。

                      【讨论】:

                        【解决方案17】:
                            Class A
                        {
                          private int i;
                        
                          int getValue()
                            {
                              return i;
                          }
                        }
                        class B extends A
                        {
                           void getvalue2()
                            {
                              A a1= new A();
                              sop(a1.getValue());
                            }
                        }
                        

                        【讨论】:

                          【解决方案18】:

                          要在子类中访问父类的私有变量,您可以使用 protected 或将 getter 和 setter 添加到父类中的私有变量中。..

                          【讨论】:

                            【解决方案19】:

                            您不能直接从外部直接访问类的任何私有变量。

                            您可以使用 gettersetter 访问私有成员。

                            【讨论】:

                              【解决方案20】:

                              在子类中访问超类私有成员的方法:

                              1. 如果您想访问包,只需将私有字段更改为受保护。它允许访问相同的包子类。
                              2. 如果您有私有字段,那么只需提供一些访问器方法(getter),您就可以在您的子类中访问它们。
                              3. 你也可以使用内部类,例如

                                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 .你也可以使用反射例如

                                 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();
                                }
                                }
                                

                              【讨论】:

                                【解决方案21】:

                                我们无法直接访问它。但是使用 Setter 和 Getter 我们可以访问,

                                代码是:

                                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    
                                    }    
                                }    
                                

                                【讨论】:

                                  【解决方案22】:

                                  您可以在代码中使用 Accessors(getter 和 setter 方法)。

                                  【讨论】:

                                    【解决方案23】:

                                    通过使用 setter 方法,您可以在反射的帮助下使用 else,您可以通过设置该成员来使用类的私有成员,例如 - 上课 并设置 a.setAccessible(true);

                                    【讨论】:

                                      【解决方案24】:

                                      您可能希望将其更改为受保护。 请参考这个

                                      https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

                                      如果这是你必须不惜一切代价去做的事情,你可以使用反射。它将为您提供类中定义的所有变量的列表——无论是公共的、私有的还是受保护的。这肯定有它的开销,但是是的,它可以让你使用私有变量。有了这个,您可以在任何课程中使用它。它不必只是一个子类 请参考以下示例。这可能有一些编译问题,但你可以得到基本的想法并且它可以工作

                                      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();
                                      
                                                  }
                                              }
                                      

                                      希望这会有所帮助。 快乐学习:)

                                      【讨论】:

                                        【解决方案25】:

                                        下面是子类对象中访问父类私有成员的例子。

                                        我正在使用构造函数来做同样的事情。

                                        下面是超类 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;
                                            }
                                        
                                        }
                                        

                                        下面是从 Fruit 继承的子类 Guava

                                        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;
                                            }
                                        }
                                        

                                        下面是我们创建子类对象并显示超类成员的主要功能。

                                        public class Main {
                                        
                                            public static void main(String[] args) {
                                        
                                                Guava G1=new Guava("kanpuria", "red");
                                                System.out.println(G1.getName()+" "+G1.getType());
                                        
                                            }
                                        
                                        }
                                        

                                        【讨论】:

                                          【解决方案26】:

                                          请注意,子类可能可以访问超类的私有字段(例如,如果两个类都是同一类的成员),但是,永远不会继承私有字段 通过子类

                                          【讨论】:

                                          • 父类的私有字段不能被子类(直接)访问。
                                          • 另一方面,受保护的字段可以由子类直接访问。
                                          【解决方案27】:

                                          简单!!!

                                          public class A{
                                          private String a;
                                          private String b;
                                          //getter and setter are here
                                          }
                                          

                                          public class B extends A{
                                          public B(String a, String b){ //constructor
                                          super(a,b)//from here you got access with private variable of class A
                                          }
                                          }
                                          

                                          谢谢

                                          【讨论】:

                                            【解决方案28】:

                                            修饰符是您添加到这些定义中以更改其含义的关键字。 Java 语言有多种修饰符,包括:

                                            • Java 访问修饰符
                                            • 非访问修饰符

                                            要使用修饰符,您需要在类、方法或变量的定义中包含其关键字。修饰符在语句的其余部分之前。

                                            这里有更多信息:

                                            http://tutorialcorejava.blogspot.in/p/java-modifier-types.html

                                            【讨论】:

                                              猜你喜欢
                                              • 2011-11-05
                                              • 2016-03-08
                                              • 2012-06-04
                                              • 1970-01-01
                                              • 2010-10-23
                                              • 2015-09-25
                                              • 2013-08-06
                                              • 2015-11-27
                                              相关资源
                                              最近更新 更多