内部类解读

     内部类对于新手来说就像是个谜团,极少接触到,也极少用到,更加不知道在什么场景下使用内部类。内部类就是将一个类(内部类)的定义放入另一个类(外围类)的定义内部。内部类更多的是辅助外围类,可以理解为外围类需要一个独立的类来帮助他完成工作。今天我们来介绍一下内部类一些比较常见的用法和特性。
下面先来介绍下内部类的基本用法。
     创建一个内部类其实很简单,下图就是一个最简单的定义。(创建内部类、内部类和外围类的互相引用、在方法和作用域中的内部类)

//外围类
public class OutClass {
    //内部类
    class InnerClass{


    }
}

链接到外部类

     内部类无论是在类、方法或者区域块中都可以可以访问外围的成员和元素,而不需要任何特殊条件(外围类在创建了内部类对象以后也可以访问内部类的成员和元素)

public class OutClass {
    private String s="this is a OutClass!";
    private void output(){
        System.out.println(s);
    }


    class InnerClass{
        private String inner ="this is a inner attribute!";
        //修改并输出外围类私有属性s
        public void innerOutPut(){
            OutClass.this.s = "this is a innerClass!";
            output();
        }
    }
    //输出内部类私有属性inner
    public void visitInnerClass(){
        InnerClass innerClass = new InnerClass();
        System.out.println(innerClass.inner);
    }


    public static void  main(String[] args){
        OutClass o = new OutClass();
        InnerClass i = o.new InnerClass();
        o.visitInnerClass();
        i.innerOutPut();
    }
}

     上图在创建内部类对象的时候用到了.new的形式在其他对象中创建内部类对象(注意必须使用外围类的对象来创建内部类对象)。在内部类中可以通过对象名+.this的方式引用外围类的属性,当然也可以不写,java会自动默认这种方式。
     但是,内部类作用于方法和作用域时,在方法和作用域之外不能直接访问在其中的内部类;当内部类作用于方法中时,可以通过向上转型将方法中的内部类对象引用到了外部,所以方法结束并不意味着内部类对象就不可用了。


匿名内部类以及jdk8的新特性:


     匿名内部类应该是这些内部类中最常用的一种类型,他的写法比普通的内部类简单许多,通过new表达式返回的引用被自动向上转型为对接口的引用:

public class OutClass implements OutClassInterface{


    public InnerClassInterface innerClassInterface(){
        return new InnerClassInterface() {
            @Override
            public void innerOutPut() {
                System.out.println("hello world!");
            }
        };
    }

     匿名内部类比较多的应用在回调领域,下面是一段判断zk节点是否存在的代码,其中就用匿名内部类作为回调函数,因为有时候一个对象方法的内容是根据具体情况改变的,使用匿名内部类可以很好的解决方法变化频繁,对象确是固定的问题;匿名内部类的关注点是重写方法,而不是对象的复用,所以不需要实际的已声明的对象。

//设置监视点
public  void maseterExists(){
    zooKeeper.exists("/master",new Watcher() { //得到通知 主节点状态变化,竞选主节点
        @Override
        public void process(WatchedEvent event) {
            if(event.getType().equals(Event.EventType.NodeDeleted)){
                assert "/master".equals(event.getPath());
                runForMaster();
            }
        }
    },masterExsistCallback,null);
}

    这里顺便介绍下jdk8新增的特性lambda表达式,下面的写法更简单:

//设置监视点
public void maseterExists() {
    zooKeeper.exists("/master", (event) -> { //得到通知 主节点状态变化,竞选主节点
        if (event.getType().equals(Event.EventType.NodeDeleted)) {
            assert "/master".equals(event.getPath());
            runForMaster();
        }
    }, masterExsistCallback, null);
}

内部类的继承与覆盖:


    内部类和外围类是相互独立的类,所以在继承和覆盖外围类的时候都不会影响的内部类,除非直接继承和覆盖内部类。


嵌套类:


    将内部类声明为static通常叫做静态内部类 也叫嵌套类。嵌套类和外围类之间没有直接关联,所以嵌套类的创建不需要外围类对象就可以直接new一个嵌套类对象new InnerClass(),这里还有一个细节点就是在声明嵌套类的时候也可以带上外围类名比如new OutClass .InnerClass();由于static的特性,嵌套类不能调用外围类中非静态的元素和成员,但是嵌套类内部可以包含静态和非静态方法和属性,这一点和内部类有所区别,内部类是不能声明static的。
    嵌套类还有一个方便的使用就是在接口中声明嵌套类,在接口中声明的内部类会隐性的加上static,实例化的方式和在类中的嵌套类是一样的。用于给接口的不同实现提供公共嵌套类,实现了该接口的类可以当做是自己的嵌套类使用。

public interface OutClassInterface {
    public void outPut();
    //接口嵌套类 隐式声明为static
    class  test implements OutClassInterface {
        public void outPut(){
        }
    }
}

       静态内部类有一个重要的应用就是单例模式,利用了classloader的机制来保证初始化instance时只有一个线程,所以是线程安全的,同时没有性能损耗。

public class OutClass implements OutClassInterface{
    public static OutClass getInstance(){
        return staticClassLazy.outClass;
    }
    @Override
    public void outPut(){
        System.out.println("");
    }
    static class staticClassLazy{
        private static OutClass outClass = new OutClass();
    }
}

 

看完java编程思想的内部类,这些是我的读后感和笔记,第一次写还请多多指教。

 

猜你喜欢

转载自blog.csdn.net/qq_27113771/article/details/80170942