linkin大话面向对象--内部类

  • 内部类说白了就是类中有类
内部类:嵌套类

外部类:宿主类


  • 内部类主要有以下作用:记住了3个字:多继承。。。
1,内部类提供了更好的封装,可以把内部类隐藏在外部类中,不允许同一个包中的其他类访问该类。
2,内部类可以访问外部类的私有数据,外部类不能访问内部类的实现细节,比如字段。
3,匿名内部类适合用于那些仅需要一次使用的类。比如在命令模式中,当需要传入一个Command对象时,使用匿名内部类将更加方便。


  • 内部类分类,主要有下面4种:
非静态内部类;静态内部类;局部内部类;匿名内部类

  • 非静态内部类
值得注意的是:外部类的上一级程序单元是包,所以他只有2个作用域:public和默认的default。

       内部类的上一级程序单元是外部类,他就有4个作用域:可以使用任意的访问控制符。


/**
 * 
 * @version 1L
 * @author LinkinPark
 * @since 2014-11-5
 * @motto 梦似烟花心似水,同学少年不言情
 * @desc ^在linkin类中定义一个binger的非静态内部类,并在binger类的实例方法中直接访问linkin的实例属性
 * 
 */
public class Linkin {
    private String name = "LinkinPark";

    private class Binger {
        private String andress = "Binger";

        public String getAndress() {
            return andress;
        }

        public void setAndress(String andress) {
            this.andress = andress;
        }

        // 非静态内部类的实例方法
        public void test() {
            System.out.println("内部类中的属性" + andress);
            System.out.println("外部类中的属性" + name);
        }
    }
    
    //外部类的实例方法
    public void test(){
        Binger binger = new Binger();
        binger.test();
    }
    
    public static void main(String[] args) {
        Linkin linkin = new Linkin();
        linkin.test();
    }

}


编译上面的程序,可以看到文件所在路径生成了2个class文件:


成员内部类(包括静态内部类,非静态内部类)的class总是这样子:OutClass$ InnerClass.class。

注意上面的代码:当调用非静态内部类的实例方法时,必须要有一个非静态内部类的实例,而且这个实例必须寄存在外部类实例中。

那么问题来了:若外部类字段,内部类字段,内部类方法变量同名,则具体的访问方式是怎么样的呢?

1,访问外部类的字段:外部类类名.this.字段

2,访问内部类字段:this.字段

3,访问内部类方法的局部变量:字段

代码如下:

public class Linkin {
    private String name = "LinkinPark...";

    private class Binger {
        private String name = "Binger...";

        // 非静态内部类的实例方法
        public void test() {
            String name = "huhu...";
            System.out.println("局部变量的属性" + name);
            System.out.println("内部类中的属性" + this.name);
            System.out.println("外部类中的属性" + Linkin.this.name);
        }
    }
    
    //外部类的实例方法
    public void test(){
        Binger binger = new Binger();
        binger.test();
    }
    
    public static void main(String[] args) {
        Linkin linkin = new Linkin();
        linkin.test();
    }

}


  • 在外部类以内访问非静态内部类

非静态内部类对象必须寄存在外部类对象中,但是外部类对象不一定非要有非静态内部类对象寄存其中。

因此外部类对象访问非静态内部类成员时,可能非静态内部类对象就压根没存在,反过来:要是非静态内部类对象访问外部类成员时,外部类对象一定存在的。

public class Linkin {
    private String name = "LinkinPark...";

    private class Binger {
        private String name = "Binger...";
        private String huhu = "Binger...";

        // 非静态内部类的实例方法
        public void test() {
            String name = "huhu...";
            //注意了:java不允许在非静态内部类中定义静态成员:包括静态方法,静态属性,静态初始化块。。。
            //static String name = "huhu...";
            System.out.println("局部变量的属性" + name);
            System.out.println("内部类中的属性" + this.name);
            System.out.println("外部类中的属性" + Linkin.this.name);
        }
    }
    
    //外部类的实例方法
    public void test(){
        //注意了:外部类不允许直接访问非静态内部类的实例属性,如果确实需要访问的话,必须显式new内部类对象出来
        //System.out.println(huhu);
        System.out.println(new Binger().huhu);
        Binger binger = new Binger();
        binger.test();
    }
    
    public static void main(String[] args) {
        //注意了:外部类的静态成员也不可以直接使用非静态内部类,下行代码编译报错。
        //new Binger();
        Linkin linkin = new Linkin();
        linkin.test();
    }

}

  • 在外部类以外访问非静态内部类
内部类不能是private修饰,否则不能访问,外部类以外的地方定义内部类变量。类型:OuterClass.InnerClass varName。

非静态内部类对象是存放在外部类的对象里的,因此在创建非静态内部类对象之前,必须先创建其外部类的对象。OuterInstance.new InnerClass([参数列表])。

class Linkin {
    String name = "LinkinPark...";

    class Binger {
        String name = "Binger...";
        
        public Binger(){
        }
        
        public Binger(String name){
            this.name = name;
        }

        public void test() {
            System.out.println("帝王注定孤独,江山与他何干...");
        }
    }
    
}

//其实在外部类中或者外部类外创建内部类对象(比如一个子类对象),都要使得内部类保持外部类对象的一个引用。
//前者可以通过外部类对象直接new内部类出来,后来将外部类作为参数传入内部类的子类构造器中。
public class LinkinTest extends Linkin.Binger{
    
    //No enclosing instance of type Linkin is available due to some intermediate constructor invocation
    //下面的构造器必须在,而且还要必须传入一个外部类,因为非静态内部类对象中必须存在一个外部类对象的引用的
    public LinkinTest(Linkin linkin){
        linkin.super();
        //linkin.super("huhu");
    }
    public static void main(String[] args) {
        //创建内部类对象
        Linkin.Binger binger = new Linkin().new Binger("忽忽");
        //访问属性
        System.out.println(new Linkin().name);//LinkinPark...
        System.out.println(new Linkin().new Binger().name);//Binger...
        System.out.println(new Linkin().new Binger("忽忽").name);//忽忽
    }
    
}


  • 静态内部类

使用static修饰内部类,该内部类属于其外部类,而不属于外部类的实例;静态内部类可包括静态成员也可包括非静态成员。

根据静态成员不能访问非静态成员的规定,所以静态内部类不能访问外部类实例成员,只能访问外部类的静态成员。即使是静态内部类的方法也不可以。

为毛静态内部类实例方法中也不能访问外部类的实例属性?

静态内部类对象不是寄存在外部类对象中的,而是寄存在外部类的类中。如果允许上面的操作,但是找不到外部类的实例对象,肯定要引起错误的呀。

/**
 *
 * @version 1L
 * @author  LinkinPark 
 * @since   2014-11-5
 * @motto   梦似烟花心似水,同学少年不言情
 * @desc    ^static不可以修饰外部类,但是可以修饰内部类
 */
class Linkin {
    String name1 = "LinkinPark...";
    static String name3;

    static class Binger {
        String name2 = "Binger...";
        
        public Binger(){
        }
        
        public Binger(String name2){
            this.name2 = name2;
        }

        public void test() {
            //Cannot make a static reference to the non-static field name1
            //静态成员不能访问非静态成员
            //System.out.println(name1);
            System.out.println(name3);
        }
    }
    
}


  • 在外部类之内访问静态内部类

public class Linkin {
    private String name = "LinkinPark";
    private static int age = 25;


    static class Binger {
        private String name1 = "Binger";
        private static int age1 = 24;


        public void show() {
            // System.out.println(name);不能访问:静态的不能访问非静态的
            System.out.println(new Linkin().name);// 可以访问
            System.out.println(age);// 可以访问
        }
    }


    public void test() {
        // System.out.println(name1);不能访问
        // System.out.println(age1);不能访问
        System.out.println(new Binger().name1);
        System.out.println(Binger.age1);
        new Binger().show();
    }


    public static void main(String[] args) {
        new Linkin().test();//Binger 24 LinkinPark 25
    }
}



  • 在外部类以外访问静态内部类

因为静态内部类是外部类的类成员,因此在创建内部类对象时不需创建外部类的对象;

创建内部类对象:new OuterClass.InnerClass([参数列表])。注:静态内部类的全名应该是OuterClass.InnerClass,所以要看作是一个整体。

public class Linkin {
    static String name3;


    static class Binger {
        static String name2;
        public void show(){
            System.out.println("静态内部类实例方法...");
        }
        public static void staticShow(){
            System.out.println("静态内部类静态方法...");
        }
    }


    public static void main(String[] args) {
        Linkin.Binger binger = new Linkin.Binger();
        Linkin.Binger.staticShow();//调用静态内部类静态方法
        binger.show();//调用静态内部类的实例方法
    }
}

  • 局部内部类

对于局部成员而言,不管是局部变量,还是局部内部类,他们的上一级程序单元是方法,而不是类,所以使用static完全没有意义。不仅如此,因为局部成员的作用域是所在的方法,其他程序单元永远不能访问另一个方法中的局部变量,所以局部变量不可以使用访问控制符修饰。

局部内部类:定义在方法里的内部类。

特点:不能在宿主类以外的地方使用,局部内部类也不能使用访问修饰符和static修饰。

局部内部类只能访问方法中final修饰的局部变量:因为final修饰的变量相当于一个常量,其生命周期超出了方法运行的生命周期。

关于上面这一点,我也不是很懂,记住就好了。其实一般也不会在一个方法中来定义一个内部类,这个有点复杂了,就好比不会在一个接口里面定义一个内部接口,我是没见过。

public class Linkin {
    public void test(){
        class Binger{
            
        }
        class Binger1{
            
        }
    };
    public static void main(String[] args) {
        final int age = 0;
        class Binger{
            String name;
            public void test(){
                //注意了:局部内部类中访问局部变量必须使用final修饰那个变量
                System.out.println(age);
            }
        }
        class Binger1 extends Binger{
            String name1;
        }
        Binger1 binger1 = new Binger1();
        binger1.name = "LinkinPark...";
        binger1.name1 = "binger...";
        System.out.println(binger1.name+"---"+binger1.name1);
    }
}

编译上面的程序看到有5个class,这表明局部内部类的class文件总是以下命名方式:OutClass$InnerClass.class,注意到局部内部类的文件名的class文件比内部类的class文件多了一个数字,这是因为同一个类中不可能有2个同名的成员变量,但是同一个类中可能有2个或者2个以上的同名的局部内部类,所以java为局部内部类的class文件增加了一个数字,用于区分。


  • 匿名内部类

适合只使用一次的类。1,不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建匿名内部类的对象,2,匿名内部类不能定义构造器,因为匿名内部类没有类名。
格式:new 父类构造器([实参列表]) 或 接口()
   {
//匿名内部类的类体部分
   }
注意:匿名内部类必须继承一个父类或者实现一个接口,但最多只能一个父类或实现一个接口;

创建匿名[Anonymity]内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。匿名内部类访问局部变量时也必须使用final修饰那个变量。


<pre name="code" class="java">public class Linkin {
    //定义一个方法,其中的参数要用到下面的抽象类
    public static void test(Binger binger){
        System.out.println(binger.getName());
        System.out.println(binger.test());
    }
    //定义一个方法,其中的参数要用到下面的接口
    public static void test1(Ihuhu huhu){
        System.out.println(huhu.test());
    }
    public static void main(String[] args) {
        //直接传入一个匿名内部类,只是在调用这个方法的时候使用一次
        Linkin.test(new Binger(){

            @Override
            //这里是必须要实现的抽象方法
            public String test() {
                return "这里把name的get方法返回了。。。";
            }
            
            @Override
            //匿名内部类当然可以重写继承过来的方法
            public String getName() {
                return "linkinPark...";
            }
            
        });
        
        Linkin.test1(new Ihuhu(){
            
            @Override//必须要实现接口里面的所有的方法呀
            public String test() {
                return "huhu...";
            }
            
        });
    }
}

abstract class Binger{
    private String name = "binger...";
    public Binger(){
        
    }
    public Binger(String name){
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //定义一个抽象方法
    abstract public String test();
}

interface Ihuhu{
    public String test();
}









原文地址:https://www.cnblogs.com/LinkinPark/p/5233156.html