菜鸡的Java笔记 第二十六 内部类 innerClass

/*    innerClass
        从实际的开发来看,真正写到内部类的时候是在很久以后了,短期内如果是自己编写代码,几乎是见不到内部类出现的
        讲解它的目的第一个是为了解释概念,另外一个就是也是为后期的一些复杂程序做铺垫
        
        所谓的内部类指的是在一个类的内部(外部类)定义类结构的一种处理形式

*/

/*    内部类的基本概念
        类的组成永远都是只有两点:成员(Field),方法(Method),但是几乎所有的程序里面斗不会对嵌套的结构有任何的限定
        所以内部类指的是在一个类的内部可以继续嵌套其他类结构的一种形式代码
        并且从理论上来讲可以一直嵌套下去
        下面首先来看一下内部类的基本形式
        范例:观察内部类代码

    class Outer{  // 外部类
        private String info = "Hello World!":
        class lnner{  // 内部类
            public void print(){
                System,out.println(Outer.this.info):  // 输出info 属性内容
            }
        }
        public void fun(){
            lnner in = new lnner():  //实例化内部类对象
            in.print():  // 调用内部类的方法
        }
    }
    public class innerClass{
        public static void main(String args[]){
            Outer out = new Outer():
            out.fun():
        }
    }
    // 结果 Hello World!

           
            类本身的核心组成就应该是属性和方法,但是如果引用了内部类,就相当于破坏了这样的程序结构
            所以内部类所带来的最为严重的问题就在于程序结构的破坏,但是破坏了那么也应该有一些收益
             那么内部类的好处在哪里呢?为了观察出内部类的好处,那么下面将内部类拿出来,变为两个类
        范例:内部类拿出来

    class Outer{  // 外部类
        private String info = "Hello World!":
        
        public void fun(){
            // 将当前对象传递到内部类之中
            lnner in = new lnner(this):  //实例化内部类对象
            in.print():  // 调用内部类的方法
        }
        // 为in定义一个getter方法
        public String getlnfo(){
            return info:
        }
    }
    class lnner{  // 内部类
        private Outer temp: // 此处应该接收外部类实例化好的Outer类对象
        public lnner(Outer temp){
            this.temp = temp:
        }
        public void print(){
            // 此处需要访问外部类中的私有属性,所以不能够直接输出属性,需要Outer类提供有getter
            // 方法应该由对象进行调用,所以现在需要有一个实例化对象
            // 相当于就是外部的out。getlnfo()
            System,out.println(this.temp.getlnfo()):  // 输出info 属性内容
        }
    }
    public class innerClass{
        public static void main(String args[]){
            Outer out = new Outer():
            out.fun():
        }
    }
    // 结果 Hello World!


            代码修改完成之后实际上就可以感受到内部类的最大好处是可以直接进行外部类中私有属性的直接访问
            那么清楚内部类的基本定义之后,实际上现在又会存在有一下几个问题:
                1.在编写代码一直强调:只要是属性的访问,一定要加上“this ”,这个时候由于属性是外部类中的
                所以要想操作this 那么就必须使用“外部类.this.属性”  ( 上面: Outer.this.info)
                
                如果内部类中的方法直接采用了“this.属于”表示的是什么,只是本类(内部类)中的属性
                
                2.以上的代码发现内部类可以方便访问外部类中的私有属性,同时发现外部类中的fun()方法里面也占着内部类的对象
                那么内部类的私有属性外部类也可以直接利用对象访问            

    class Outer{  // 外部类
        private String info = "Hello World!":
        class lnner{  // 内部类
        private String msg = "+++++++++"://  内部类的私有属性
            public void print(){
                System,out.println(Outer.this.info):  // 输出info 属性内容
            }
        }
        public void fun(){
            lnner in = new lnner():  //实例化内部类对象
            in.print():  // 调用内部类的方法
            System.out.println(in.msg):// 内部类对象直接调用属性
        }
    }
    public class innerClass{
        public static void main(String args[]){
            Outer out = new Outer():
            out.fun():
        }
    }
    /*
    结果
    Hello World!
    ++++++++++++
    */

               
                内部类与外部类之间的私有属性都是可以直接进行访问的,这一点要比分为两个类更加的方便
                
                3.现在发现实例化内部类的对象操作都是在外部类中的fun()方法里面完成的
                那么如果现在不希望通过外部类的方法操作内部类,那么也可以根据一下的语法,直接在其他类实例化内部类对象
                语法结构:
                    外部类名称.内部类名称 对象名称 = new 外部类().内部类()
                    内部类的标准的名称应该是“外部类.内部类”,只不过“.”不可能直接出现在文件中
                    所以java 将其进行了转换,在文件名称中使用“$”来代替“.”               

    class Outer{  // 外部类
        private String info = "Hello World!":
        class lnner{  // 内部类
            public void print(){
                System,out.println(Outer.this.info):  // 输出info 属性内容
            }
        }
    }
    public class innerClass{
        public static void main(String args[]){
            Outer.lnner in = new Outer().new lnner():
            in.print():
        }
    }
    //  结果 Hello World!


4.内部类中可以利用private定义私有内部类:

    class Outer{  // 外部类
        private String info = "Hello World!":
        private class lnner{  // 内部类
            public void print(){
                System,out.println(Outer.this.info):  // 输出info 属性内容
            }
        }
    }
    public class innerClass{
        public static void main(String args[]){
            Outer.lnner in = new Outer().new lnner():
            in.print():
        }
    }
    // 结果: 出错  

                对于内部类的概念与它的结构有个先期的认识即可
                
*/

/*    内部类定义深入
        在之前使用的都是普通类的形式进行了内部类的定义,实际上在内部结构上也可以应用在抽象类和接口上
        
        范例:在抽象类上定义内部类

    abstract class AbstractOuter{ // 抽象类的外部类
        public abstract void peintOuter();
        abstract class AbstractInner{ // 抽象内部类
            public abstract void printInner();
        }
        class Inner{ // 普通的内部类
            public void print(){
                System.out.println("加油!");
            }
        }
    }
    class OuterImpl extends AbstractOuter{ // 继承了外部抽象类
        public void peintOuter(){
            new Inner().print();  // 实例化内部类的对象调用方法
        }
    }
    public class innerClass{
        public static void main(String args[]){
            AbstractOuter out = new OuterImpl();
            out.peintOuter();
        }
    }

           
            在定义内部抽象类的时候是不会影响到子类的,也就是说子类只需要覆写它所继承的抽象类中的抽象方法即可
            
        范例:定义内部抽象类的子类

abstract class AbstractOuter{ // 抽象类的外部类
    public abstract void peintOuter();
    abstract class AbstractInner{ // 抽象内部类
        public abstract void printInner();
    }
    class Inner{ // 普通的内部类
        public void print(){
            System.out.println("加油!");
        }
    }
}
class OuterImpl extends AbstractOuter{ // 继承了外部抽象类
    public void peintOuter(){
        new Inner().print();  // 实例化内部类的对象调用方法
    }
    class InnerImpl extends AbstractInner{ // 内部抽象类
        public void printInner(){
            new Inner().print();
        }
    }
}
public class innerClass{
    public static void main(String args[]){
        AbstractOuter.AbstractInner in = new OuterImpl(),new InnerImpl();
        in.peintOuter();
    }
}

           
            除了内部抽象类之外也可以实现内部的接口定义
            
        范例:定义内部接口

interface IOuter{
    public void peintOuter();
    interface IInner{
        public void printInner();
    }
    class B{
        public void print(){
            System.out.println("++++++++");
        }
    }
}
class OuterImpl implements IOuter{
    public void peintOuter(){
        class InnerImpl implements IInner{
            public void printInner(){
                new B().print();
            }
        }
    }
}
public class innerClass{
    public static void main(String args[]){
        IOuter.IInner in = new OuterImpl().new InnerImpl();
        in.printInner();
    }
}

           
            内部类完整的打破了程序结构定义要求,也就是说程序里面没有对内部类的结构做出任何的限制,只要该定义符合语法要求即可使用

*/


/*    利用static定义内部类
        利用static定义的属性或者是方法,是不受到类的控制的,也就是说相当于是一个局外的结构
        所以如果内部类上用了static定义,那么就表示此内部类变为了一个外部类,但是需要注意的是,如果它使用了static定义,那么只能够访问外部类中的static属性
        范例:利用static定义内部类

    class Outer{  // 外部类
        private static String info = "Hello World!":
        static class lnner{  // 内部类
            public void print(){
                System.out.println(info):  // 输出info 属性内容
            }
        }
    }
    public class innerClass{
        public static void main(String args[]){
            
        }
    }

           
            那么既然现在static的内部类变为了外部类,外部类就可以被其他类直接进行操作
            但是这个时候的实例化对象格式:
                外部类名称.内部类名称 对象名称 = new 外部类.内部类():
            加上了static之后,那么实际上也就表示这个内部类的名字就成了“外部类.内部类”
        范例:实例化内部类对象    

class Outer{  // 外部类
    private static String info = "Hello World!":
    static class lnner{  // 内部类
        public void print(){
            System.out.println(info):  // 输出info 属性内容
        }
    }
}
public class innerClass{
    public static void main(String args[]){
        Outer.lnner oi = new Outer.lnner():
        oi.print():
    }
}
// 结果 Hello World!

           
            以后见到程序类库中出现有“Xxxx.Xxxx”就表示内部类
            
        对于 static 定义内部类的形式在实际开发之中使用很多,但是也可以在接口上使用,即:接口内部可以使用 static 定义外部接口
            
        范例:

interface IOuter{
    static interface IInner{  // 静态的内部接口
        public void print();
    }
}
class InnerImpl implements IOuter.IInner{
    public void print(){
        System.ou.println("+++++++++");
    }
}
public class innerClass{
    public static void main(String args[]){
        IOuter.IInner oi = new InnerImpl():
        oi.print():
    }
}

 

*/

/*    方法中定义内部类
        理论上内部类可以在任何的位置上定义,包括:代码块中,类中,方法中。所以在实际的开发之中,有可能直接在方法里使用内部类
        范例:观察方法中定义内部类

class Outer{  // 外部类
    private String info = "Hello World!":
    public void dun(int temp){  // 方法中的参数
        double sal = 9000.0:  // 方法中定义的普通变量
        class lnner{  // 内部类,方法中定义
        public void print(){
            System.out.println("Outer类中的info属性= "+Outer.this.info):
            System.out.println("fun()方法中的参数,temp = "+temp):
            System.out.println("fun()方法定义的临时变量,sal ="+sal):
            }
        }
        new lnner().print():// 实例化内部类对象,调用方法输出
    }
}
public class innerClass{
    public static void main(String args[]){
        Outer out = new Outer():// 实例化Outer类对象
        out.fun(100):
    }
}
/*
结果
Outer类中的info属性= Hello World!
fun()方法中的参数,temp = 100
fun()方法定义的临时变量,sal = 9000.0
*/

           
            注意:现在使用的是JDK1.8版本
                那么这个版本的好处是避免了一些复杂的细节,之所以会避免是为了整体的设计考虑的,而以上的代码,在JDK1.7时就会出现问题
                因为在JDK1.7以前有一个约定,如果一个方法中定义了内部类,那么这个内部类要想访问方法的参数或者是定义的变量,则参数或者是变量前必须加上final
                之所以可以不加final了,主要是因为那个Lamde与方法引用一起出现所造成的新局面
*/

/*    anonymousInternal 匿名内部类
        匿名内部类的使用
        
    内容
        匿名内部类 = 没有名字的内部类
        任何的技术出现都有它可以解决的问题,所以下面首先来分析一下没有匿名内部类的情况
        范例:观察程序代码的问题

interface A{// 定义了一个接口
    public void ptintA();
}
class X implements A{
    public void ptintA(){
        System.out.println("AAAAAAAAAAAAAAA");
    }
}
publlic class anonymousInternal{
    publlic static void main(String args[]){
        A a = new X();
        a.ptintA();
    }
}

           
            有了一个接口,而后为接口定义了一个子类,在主类中利用对象的向上转型进行对象实例化操作
        但是现在有一个问题出现了,本程序中为接口A定义了一个子类X,但是假设说此时的这个X子类只使用唯一的一次
        那么有必要将其定义成一个单独的类吗?那么此时的设计就有些夸张了。
        那么就可以利用匿名内部类的概念来解决,而且匿名内部类必须以抽象类或接口为前提进行使用
        范例;使用匿名内部类

interface A{// 定义了一个接口
    public void ptintA();
}
public class anonymousInternal{
    public static void main(String args[]){
        A a = new A(){ // 匿名内部类
            public void ptintA(){
                System.out.println("***********************");
            }
        }
        a.ptintA();
    }
}            

            现在的基本感觉此语法很槽糕,程序的结构很混乱
                    
        范例:

abstract class AbstractA{
    private String mdg = "+++++++++++++";
    public String getMsg(){
        return this.msg;
    }public abstract void print();
}
public class anonymousInternal{
    public static void main(String args[]){
        AbstractA a = new AbstractA(){ // 匿名内部类
            public void ptint(){
                System.out.println(this.getMsg());
            }
        }
        a.ptintA();
    }
}

           
            匿名内部类的最大特点是可以减少类的定义个数,所以在以后的开发之中会大量的使用匿名内部类来进行某些接口子类的定义
            这一点在后面讲解的多线程开发之中非常有用处,同时匿名内部类也是 Lembda 表达式的原始雏形         
    
    总结
        可以看懂匿名内部类就够了,其他的慢慢随着代码的编写经验的增长自然就会了

*/

/*    总结
        1.不要去考虑怎么用,一般的开发很少会用到,但是会使用
        2.内部类先看明白它的语法形式

*/

猜你喜欢

转载自www.cnblogs.com/mysterious-killer/p/10121917.html