Java编程思想之内部类

内部类 : 可以将一个类的定义放在另一个类的定义内部,内部类允许把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性。

/***
 * 内部类的创建 把类定义在外部类里面
 * @author YuSheng_
 *
 */
public class Outer {

    class FisrtInner {
        public void firstMethod() {
            System.out.println("FisrtInner的方法........");
        }
    }

    class SecondInner {
        private String msg;
        SecondInner(String str) {
            msg = str;
        }
        public void secondMethod() {
            System.out.println(msg);
        }
    }
    /***
     * 外部类中的方法
     * 这个方法返回一个指向内部类的引用
     * @param str
     */
    public void useInnerClass(String str) {
        FisrtInner fisrtInner = new FisrtInner();
        fisrtInner.firstMethod();
        SecondInner secondInner = new SecondInner(str);
        secondInner.secondMethod();
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.useInnerClass("巅峰迎来虚伪的看客,黄昏见证真正的信徒!");
    }
}

在外部类的非静态方法之外的任意位置创建某个内部类的对象
要具体的指明这个对象的类型 OuterClassName.InnerClassName

public class Outer {

    class FirstInner {
        public void firstMethod(String str) {
            System.out.println("firstMethod执行........" + str);
        }
    }

    class SecondInner {
        public void SecondMethod(String str) {
            System.out.println("SecondMethod执行......." + str);
        }
    }

    public FirstInner getFirstInner() {
        return new FirstInner();
    }

    public SecondInner getSeconInner() {
        return new SecondInner();
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        FirstInner firstInner = outer.getFirstInner();
        firstInner.firstMethod("海上月是天上月");
        SecondInner seconInner = outer.getSeconInner();
        seconInner.SecondMethod("眼前人是心上人");
        //OuterClassName.InnerClassName
        FirstInner firstInner2 = new Outer().new FirstInner();
        firstInner2.firstMethod("你说啥?");
    }
}

在内部类中可以链接到外部类
意思就是内部类自动拥有对其外部类所有成员的访问权。
当某个外部类的对象创建了一个内部类对象时,此内部类对象必定会秘密捕获一个指向那个外部类对象的引用。
可以看看大手子的文章:

深入理解Java中为什么内部类可以访问外部类的成员 - JAVA编程语言程序开发技术文章 - 红黑联盟
https://www.2cto.com/kf/201402/281879.html

使用.this和.new
如果要生成外部类对象的引用,使用OuterClassName.this。这样产生的引用自动地具有正确的类型

public class OuterClass {

    public void first() {
        System.out.println("调用外部类的方法......");
    }

    class InnerClass {
        public OuterClass getOuterClass() {
            return OuterClass.this;
        }

    }

    public static void main(String[] args) {
        //创建外部类对象并初始化
        OuterClass outerClass = new OuterClass();
        //通过外部类对象获取内部类对象
        InnerClass in = outerClass.new InnerClass();
        //通过内部类对象调用方法 获得外部类对象的引用
        OuterClass outerClass2 = in.getOuterClass();
        //利用外部类对象调用方法
        outerClass2.first();

    }
}

虽然上面的代码看起来是多此一举,但是也说明了.this和.new的用法。
**这里要注意的是:
在拥有外部类对象之前是不可能创建内部类对象的,这是因为内部类对象会连接到创建它的外部类对象上。但是,如果是静态内部类,那么久不需要对外部类对象的引用了。.**

内部类的向上转型

public class OuterClass02 {
    public static void main(String[] args) {
        Pracel pracel = new Pracel();
        Des des = pracel.getDes();
        des.firstMethod();
        Ant ant = pracel.getAnt();
        ant.secondMethod();
    }
}

interface Des {
    void firstMethod();
}

interface Ant {
    void secondMethod();
}

class Pracel {

    private class DesImpl implements Des {

        public void firstMethod() {
            System.out.println("私有内部类方法调用......");
        }

    }

    protected class AntImpl implements Ant {

        public void secondMethod() {
            System.out.println("保护内部类方法调用......");
        }

    }

    public Des getDes() {
        // 向上转型 Des des = new DesImpl();
        return new DesImpl();
    }

    public Ant getAnt() {
        // 向上转型 Ant ant = new AntImpl();
        return new AntImpl();
    }
}

这种模式指的是 现在Des和Ant这两个接口时客户端程序员可用的接口,因为在Parcel这个类中,两个内部类分别是private和protected的。所以除了Parcel这个类或者二是它的子类都不可以访问这两个内部类。所以如果客户端程序员想访问这些成员,是受到限制的。
另外,这种 private内部类给类的设计者提供了一种途径,通过这种方式,可以完全阻止任何依赖于类型的编码(可能说的是如果不用这种模式,而是使用Parcel去实现那两个接口,就限定了Parcel的类型),并且完全隐藏了所有的细节。
既然这样,我们现在写项目的时候。都是在service层,dao层先写一个接口,然后再进行实现。可不可以仍然写多个接口,然后再一个类的内部建立多个私有内部类,然后私有内部类是接口的实现。感觉是种吃力不讨好的方法。。。但是如果只想把接口给别人用,觉得还凑合啊…

在方法里面或者在任意作用域内定义内部类:

  1. 实现了某类型的接口,可以创建并返回对其的引用
  2. 要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。
public class OuterClass03 {

    public void method(String str) {

        class Inner {
            private String s;

            Inner(String string) {
                s = string;
            }

            public void InnerMehtod() {
                System.out.println(s);
            }
        }
        Inner inner = new Inner(str);
        inner.InnerMehtod();
    }

    public static void main(String[] args) {
        OuterClass03 class03 = new OuterClass03();
        class03.method("白茶清欢无别事");
    }
}

上面的代码就是将Inner类嵌入到method方法中,可以说为了打印这个问题才创建的Inner类。
同时,Inner类的作用域只限于method方法内部。在此之外,是不可用的。

匿名内部类

public class OuterClass04 {

    public Contents contents() {
        return new Contents() {
            private int i;

            public int value() {
                return 0;
            }
        };
    }

    public static void main(String[] args) {
        OuterClass04 outerClass04 = new OuterClass04();
        Contents content = outerClass04.contents();
        //看看内部类的类型
        System.out.println(content.getClass());
        Contents contents = new Contents();
        System.out.println(contents.getClass());
    }
}

class Contents {

}

打印结果:

class com.YuSheng.thinking.OuterClass04$1
class com.YuSheng.thinking.Contents

上述代码片指的是:创建一个继承自Contents的匿名类的对象,通过new表达式返回的引用被自动向上转型为对Contents的引用。
从上面的打印结果中可以看出,虽然看着像返回了一个Contents类的引用,但是其实并不是这样的。

    public Contents contents(final String str) {
        return new Contents() {
            private String i = str;

            int value() {
                return 0;
            }
        };
    }

要注意的是,如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么这个参数引用必须是final的。

关于匿名内部类的构造器,因为匿名内部类是没有名字的,所以不可能拥有构造器。但是可以通过实例初始化来达到构造器的效果。

public class OuterClass05 {

    public Luo getLuo(String s) {
        return new Luo(s) {
            {
                System.out.println("实例初始化.....");
            }

            public void f() {
                super.f();
                System.out.println("匿名内部类的f方法别调用........");
            }
        };
    }

    public static void main(String[] args) {
        OuterClass05 outerClass05 = new OuterClass05();
        Luo luo = outerClass05.getLuo("我在等风也等你");
        luo.f();
    }
}

 class Luo {
    Luo(String str) {
        System.out.println(str);
        System.out.println("Luo类的构造器调用.......");
    }

    public void f() {
        System.out.println("Luo类的f方法被调用......");
    }
}

打印结果:

我在等风也等你
Luo类的构造器调用.......
实例初始化.....
Luo类的f方法被调用......
匿名内部类的f方法别调用........

同时 ,这里super.f().的调用也证明了匿名内部类是Luo类的子类。

嵌套类

public class OuterClass06 {

    private String str;

    public void getStr(String s) {
        str = s;
    }
    public static void method02(){
        System.out.println("22");
    }

    static class InnerClass {

        public void method(String str) {
            System.out.println(str);
        }

        public static void method01() {
            System.out.println("内部类静态方法调用....");
        }
    }

    public static void main(String[] args) {
        InnerClass innerClass = new InnerClass();
        //调用普通方法需要内部类对象  但是内部类对象的创建不再依赖于外部类
        innerClass.method("硕鼠硕鼠,无食我黍");
        System.out.println(innerClass.getClass());
        //调用内部类静态方法不需要对象  直接通过类名调用
        InnerClass.method01();
    }
}

打印结果:

硕鼠硕鼠,无食我黍
class com.YuSheng.thiinking.OuterClass06$InnerClass
内部类静态方法调用....
  • 要创建嵌套类的对象,并不需要其外围类的对象
  • 不能从嵌套类的对象中访问非静态的外围类对象

接口中的内部类

书中说道: 正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分。但是放到接口中的任何类都是public和static的。因为类是static的,只是将嵌套类置于接口的命名空间中,这并不违反规则,甚至可以在内部类中实现其对外部类的接口。

public interface OuterClass07 {
    void f();

    class InnerClass {

        public void f01() {
            System.out.println("回眸一笑百魅生,六宫粉黛无颜色");
        }
    }
}
public class Test01 implements OuterClass07{

    public void f() {
        new InnerClass().f01(); 
    }
    public static void main(String[] args) {
        new Test01().f();
    }
}

上边的代码并没有在内部类汇中实现对外部类的接口。但是可以刻进行实现,并且重写方法。

关于为什么要使用内部类:

每个内部类都能独立的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口)实现,对于内部类都没有影响。

//内部类具有可以继承多个具体的或者抽象的类的能力

最近有点忙 未完待续…

猜你喜欢

转载自blog.csdn.net/m0_37607679/article/details/79219118