探讨Java内部类的可见性

简介:
Java 中,当生成一个内部类的对象时,此对象与制造它的外部类通过外部类的 .this 保持着联系,因此该内部类对象可以访问其外部类对象的所有成员,包括 private 成员。
而该内部类对象对于其他类的对象的访问,遵照常规的访问权限语法,这一点也没有什么特别支持。这里需要探讨的是,外部类以及其他类的对象可以如何访问到某个内部类对象,即内部类的可见性问题。
下面是一个示例程序 Out.java ,其中包含了 4 个不同访问权限的内部类( private,default,protected,public ),在每个内部类中,分别包含 4 个不同访问权限的成员与方法。在外部类 Out 中提供了得到内部类实例的方法。
Out.java

package  com.zj.main;

 

public   class  Out {

     public  PrivateIn getPrivateIn(){

        return   new  PrivateIn();

    }

   

     public  DefaultIn getDefaultIn(){

        return   new  DefaultIn();

    }

   

     public  ProtectedIn getProtectedIn(){

        return   new  ProtectedIn();

    }

   

     public  PublicIn getPublicIn(){

        return   new  PublicIn();

    }

   

     private   class  PrivateIn  implements  InMethod{

        private   int   private_arg ;

        int   default_arg ;

        protected   int   protected_arg ;

        public   int   public_arg ;

      

        private   void  private_method(){};

        void  default_method(){};

        protected   void  protected_method(){};

        public   void  public_method(){};

    }

   

     class  DefaultIn  implements  InMethod{

        private   int   private_arg ;

        int   default_arg ;

        protected   int   protected_arg ;

        public   int   public_arg ;

      

        private   void  private_method(){};

        void  default_method(){};

        protected   void  protected_method(){};

        public   void  public_method(){};

    }

   

     protected   class  ProtectedIn  implements  InMethod{

        private   int   private_arg ;

        int   default_arg ;

        protected   int   protected_arg ;

        public   int   public_arg ;

      

        private   void  private_method(){};

        void  default_method(){};

        protected   void  protected_method(){};

        public   void  public_method(){};

    }

   

     public   class  PublicIn  implements  InMethod{

        private   int   private_arg ;

        int   default_arg ;

        protected   int   protected_arg ;

        public   int   public_arg ;

      

        private   void  private_method(){};

        void  default_method(){};

        protected   void  protected_method(){};

        public   void  public_method(){};

    }

 

     public   static   void  main(String[] args){

        //create an outer object

       Out out= new  Out();

      

        //create a private inner object by 'new'

        Out.PrivateIn privateIn=out. new  PrivateIn();

       privateIn. private_arg =0;

       privateIn.private_method();

      

        // create a private inner object  by 'out's method'

        Out.PrivateIn privateIn2 = out.getPrivateIn();

       privateIn2. private_arg  = 0;

       privateIn2.private_method();

     }

}

所有的 4 个内部类都实现了一个接口 InMethod ,该接口的作用在下文中会有讨论。下面先讨论内部类所在的外部类对其内部类对象的访问权限问题。
1. 外部类的访问

我们通过两种两种方式试图创建内部类的实例。
方式一  OuterClassName.InnerClassName inner=new Ouer().new Inner();

通过外部类对象 .new  的方式,可以得到 private inner class  的实例,并且可以访问它的 private 成员和 private 方法。自然 default protected public 的都可以访问。
 
方式二   通过外部类方法 get InnerInstance()

此种方法也可以访问所有内部类的所有成员和方法。
所以,一个内部类的对象对生成它的外部类对象是完全可见的,包括 private 内部类、 private 成员与 private 方法。
2. 同包其他类的访问

下面,在同一个包内创建一个 SamePackage.java 类,试图访问 Out 类的所有内部类。
SamePackage.java

package  com.zj.main;

 

public   class  SamePackage {

     public   static   void  main(String[] args) {

        // create an outer object

       Out out =  new  Out();

      

        //create a private inner object by 'new'

        //Out.PrivateIn privateIn=out.new PrivateIn();

        //->error: Out.PrivateIn is not visible.

 

        // create a default inner object by 'new'

       Out.DefaultIn defaultIn = out. new  DefaultIn();

        //defaultIn.private_arg=0;->error:not visible

       defaultIn. default_arg  = 0;

        //defaultIn.private_method();->error:not visible

       defaultIn.default_method();

 

        // create a private inner object by 'out's method'

        //Out.PrivateIn privateIn2 = out.getPrivateIn();

        //->error:Out.PrivateIn is not visible through out.getPrivateIn() is visible.

      

        // create a private inner object by 'out's method',

        // but use Interface reference to handle it

       InMethod privateIn=out.getPrivateIn();

       privateIn.public_method();

    }

}

方式一  OuterClassName.InnerClassName inner=new Ouer().new Inner();
使用方式一试图得到 private  内部类失败,根本得不到内部类的句柄。
//create a private inner object by 'new'

//Out.PrivateIn privateIn=out.new PrivateIn();

//->error: Out.PrivateIn is not visible.

     但是可以正常的访问 default 访问权限的内部类的对象。当然是访问不到它的 private 成员和 private 方法的。自然 protected public 的都可以访问。
 
方式二   通过外部类方法 get InnerInstance()
虽然可以调用外部类对象的 getInnerInstance() 方法,但由于得不到 private 内部类的句柄,所以此种方法无法创建 private 内部类的实例。
// create a private inner object by 'out's method'

//Out.PrivateIn privateIn2 = out.getPrivateIn();

//->error:Out.PrivateIn is not visible through out.getPrivateIn() is visible.
但由于所有的内部类都实现了接口 InMethod
<<interface>> InMethod.java

public   interface  InMethod {

     void  public_method();

}

所以还是可以通过接口的引用访问到 private 内部类的 public 方法。自然 default protected public 的都可以访问这个 public 方法。
// create a private inner object by 'out's method',

// but use Interface reference to handle it

InMethod privateIn=out.getPrivateIn();

privateIn.public_method();
3. 不同包其他类的访问

在另一个包中建立一个类 DifferPackage.java
DifferPackage.java

package  com.zj.other;

 

import  com.zj.main.InMethod;

import  com.zj.main.Out;

 

public   class  DifferPackage {

     public   static   void  main(String[] args){

        //create an outer object

       Out out= new  Out();

      

        //create a public inner object by 'new'

       Out.PublicIn publicIn=out. new  PublicIn();

       publicIn. public_arg =0;

       publicIn.public_method();

      

        // create a public inner object by 'out's method'

       Out.PublicIn publicIn2 = out.getPublicIn();

       publicIn2. public_arg =0;

       publicIn2.public_method();

      

        //use Interface reference

       InMethod method;

       method=out.getPrivateIn();

       method.public_method();

       method=out.getDefaultIn();

       method.public_method();

       method=out.getProtectedIn();

       method.public_method();

       method=out.getPublicIn();

       method.public_method();

    }

}
通过 new 方式和 getInnerInstance() 方法只能访问 public 内部类的 public 成员和 public 方法;如果使用接口的引用,则可以访问所有 4 个内部类的 public 方法。
4. 不同包继承类的访问

在另一个包中建立一个类 DifferPackageExtend.java ,它继承自外部类 Out
DifferPackageExtend.java

package  com.zj.other;

 

import  com.zj.main.Out;

 

public   class  DifferPackageAndExtend  extends  Out{

     public   static   void  main(String[] args){

        //create an DifferPackageAndExtend's object,which extends Out

       Out extend= new  DifferPackageAndExtend();

      

        //create a protected inner object by 'new'

        //Out.ProtectedIn protectedIn=extend.new ProtectedIn();

        //->error:The constructor Out.ProtectedIn() is not visible

      

        // create a protected inner object by 'out's method'

       Out.ProtectedIn protectedIn=extend.getProtectedIn();

       protectedIn. public_arg =0;

       protectedIn.public_method();

    }

}
通过 new 方式,虽然可以得到内部类的句柄 Out.ProtectedIn ,但该内部类的构造子却不可见。
通过 getInnerInstance() 方法得到 protected 内部类的对象,但只能访问到 public 成员和 public 方法。由此可知, protected 内部类并不关心是否有其他类继承自它的外部类。所有 protected 访问权限不在此种情况下适用。


本文转自zhangjunhd51CTO博客,原文链接:http://blog.51cto.com/zhangjunhd/65624,如需转载请自行联系原作者
相关文章
|
2月前
|
Java 编译器
【Java】内部类
【Java】内部类
22 0
|
4月前
|
Java
【Java基础面试二】、个Java文件里可以有多个类吗(不含内部类)?
这篇文章讨论了Java文件中类的定义规则,指出一个Java文件可以包含多个类(不包含内部类),但其中最多只能有一个public类,且如果有public类,它的名称必须与文件名一致。
|
4月前
|
算法 Java
12 Java常用类(一)(内部类+object类+包装类)
12 Java常用类(一)(内部类+object类+包装类)
38 5
|
5月前
|
Java
Java进阶之内部类
【7月更文挑战第13天】Java内部类增进代码组织与封装,允许直接访问外部类成员,包括私有成员。主要有四种类型:成员、静态、局部和匿名内部类。匿名内部类常用于一次性实现接口或扩展类。内部类可隐藏实现细节,减少命名冲突,并在特定上下文中定义辅助类。示例展示了静态和非静态内部类如何在Shape类中封装Circle和Rectangle。使用内部类能提升代码可读性,但可能增加复杂性。
39 6
|
5月前
|
安全 Java 开发者
探索Java内存模型:可见性、有序性和并发
在Java的并发编程领域中,内存模型扮演了至关重要的角色。本文旨在深入探讨Java内存模型的核心概念,包括可见性、有序性和它们对并发实践的影响。我们将通过具体示例和底层原理分析,揭示这些概念如何协同工作以确保跨线程操作的正确性,并指导开发者编写高效且线程安全的代码。
|
4月前
|
Java
【Java】内部类、枚举、泛型
【Java】内部类、枚举、泛型
|
5月前
|
缓存 安全 Java
Java面试题:解释volatile关键字的作用,以及它如何保证内存的可见性
Java面试题:解释volatile关键字的作用,以及它如何保证内存的可见性
77 4
|
5月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
80 1
|
5月前
|
安全 Java 开发者
Java面试题:Java内存模型解析,Java内存模型的基本概念和它的重要性,Java内存模型中的“可见性”和“有序性”,以及具体实现?
Java面试题:Java内存模型解析,Java内存模型的基本概念和它的重要性,Java内存模型中的“可见性”和“有序性”,以及具体实现?
60 1
|
6月前
|
Java
一篇文章讲明白Java中内部类详解—匿名内部类
一篇文章讲明白Java中内部类详解—匿名内部类
95 2