首页 > 技术文章 > java编程入门3 内部类

ccsuCBG 2018-10-15 20:41 原文

内部类

内部类包括:成员内部类、局部内部类、匿名内部类、静态内部类

内部类对象的创建方式:外部类名.内部类名 对象名 =外部对象名.new 内部类名();

1.为什么要使用内部类

1.在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

2.在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

3.其实使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,但是如果我们不需要解决多重继承问题,那么我们自然可以使用其他的编码方式,但是使用内部类还能够为我们带来如下特性

1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

2、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

3、创建内部类对象的时刻并不依赖于外围类对象的创建。

4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。

2.成员内部类

1.成员内部类可以无条件的访问外部类的所有成员属性和成员方法 (包括private成员和静态成员)

2.当成员内部类拥有和外部类同名的成员变量或方法时,会发生隐藏现象,即在内部类中默认情况下访问的是成员内部类的成员,也可以用this访问内部类成员

如果要访问外部类的同名成员,需要用以下形式访问: 外部类.this.成员变量(成员方法)

3.外部类想要访问内部类的成员,必须先创建一个成员内部类的对象再通过对象来访问(Outter.Inner inner =outter.new Inner())。即内部类的的实例一定要绑定在外部类的实例上

4.内部类拥有private protected public default 修饰

外部类拥有public 和default 修饰

成员内部类可以看成外部类的一个成员,可以像类的成员一样拥有多种权限修饰

5.成员内部类中不能存在任何static的变量和方法

public class Circle{
    private Draw draw=null;
    private double radius=0;
    public static int count=1;
    public Circle(double radius) {
        System.out.println("构造方法");
        this.radius=radius;
    }
    public Draw getDrawInstance() {
        if(draw==null) draw=new Draw();
        return draw;
    }
    class Draw { //内部类
        private double radius=2.0;
        public void printf() {
            System.out.println(Circle.this.radius);
            System.out.println(this.radius);
            System.out.println(count);
        }
    }
}
class Test {
    public static void main(String[] args) {
        Circle circle=new Circle(5.0);
        //Circle.Draw draw =circle.new Draw();
        Circle.Draw draw=circle.getDrawInstance();
        draw.printf();
    }
}

 

3.局部内部类

1.局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内.

2.内部类是方法的一部分,而不是外部类的一部分,所以在方法的外部不能访问该内部类,但是与成员内部类一样局部内部类可以访问当前代码块的常量以及此外部类的所有成员

3.如果需要在方法体中使用局部变量,该局部变量需要被设置为final类型换句话说,在方法中定义的内部类只能访问方法中final类型的局部变量.

理由:非final的变量在方法执行完毕后会被销毁的,如果内部类的一个方法使用了该变量(引用变量)做为自己的属性,并返回了自己。此时内部类对象没有被销毁,并持有非final的引用变量的引用,而那个变量却应该被销毁。这显然是自相矛盾的。

4.局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的

class People{
    public People(){

    }
}
public class Man {
    public Man() {

    }
    public People getWoman(final String name) {
        class Woman extends People{
            Woman(String str){
                str=name;
                System.out.println(str);
            }
        }
        return new Woman("getwoman");
    }
}
class Test {
    public static void main(String[] args) {
        new Man().getWoman("name");
    }
}

 

4.匿名内部类

1.不能有public、protected、private以及static修饰符的

2.一般形式:

return new A(){

//内部类体

}

3.new 匿名内部类,这个类是要存在的类

4. 匿名内部类是没有构造方法的

5.所在方法的形参需要被匿名内部类使用时,这个形参就必须为设置为final。

interface OutInterface2{

}
public class OuterClass4 {
    public OutInterface2 doit(final int num) {
        return new OutInterface2() {
            private int i=num;
            public int getValue() {
                return i;
            }
        };
    }
}

5.静态内部类

1.如果创建静态内部类的对象,不需要其外部类的对象

2.不能在静态内部类中访问外部类的非静态成员变量和非静态成员方法

3.静态内部类中可以声明static成员,但是在非静态内部类中不可以申明静态成员。

public class StaticInnerClass {
    static class Inner{
        static int age=0;
        int a=1;
    }
    class Inner2{
        int a=2;
    }
}
class Test {
    public static void main(String[] args) {
        //静态内部类的静态变量
        System.out.println(StaticInnerClass.Inner.age);
        //静态内部类成员变量
        StaticInnerClass.Inner ob=new StaticInnerClass.Inner();
        System.out.println(ob.a);
        //非静态内部类的成员变量
        StaticInnerClass Outer=new StaticInnerClass();
        StaticInnerClass.Inner2 obj=Outer.new Inner2();
        System.out.println(obj.a);
    }
}

 

6.内部类向上转型为接口

如果将一个权限修饰符为private的内部类向上转型为其父类对象,或者直接向上转型为一个接口,在程序中就可以完全隐藏内部类的具体实现过程。

在实现该接口的内部类中实现该接口的方法,就可以定义多个内部类以不同的方式实现接口中的同一方法,而在一般的类中是不能多次实现接口中的同一方法的.这些技巧经常被应用在Swing编程中.可以在一个类中做出多个不同的响应事件。

interface OutInterface{
    public void f();
}
public class InterfaceInner {
    public static void main(String[] args) {
        OuterClass out=new OuterClass();
        OutInterface inner=out.doit();
        inner.f();
    }
}
class OuterClass{
    private class InnerClass implements OutInterface{
        InnerClass(String s){
            System.out.println(s);
        }
        public void f() {
            System.out.println("访问内部类中的f()方法");
        }
    }
    public OutInterface doit() {
        return new InnerClass("访问内部类构造方法");
    }
}

 

7.内部类的继承

在某个类继承内部类时,必须硬性给予这个类一个带参数的构造方法,并且该构造方法的参数为需要继承内部类的外部类的引用,同时在构造方法体中使用 外部类对象.super() 语句,这样才为继承提供了必要的对象引用

Java内部类的构造器必须连接到指向其外围类对象的引用(构造内部类必须给它一个外部类对象的引用,内部类依赖于外部类对象),所以在继承内部类的时候,需要在导出类的构造器中手动加入对基类构造器的调用。因为,在导出类实例化时,并不存在一个外围类对象,以让导出类的实例去连接到它。所以,我们需要创建一个外围类,然后用一个特定的语法来表明内部类与外围类的关系。

class WithInner{
    class Inner{
    }
}
public class InheritInner extends WithInner.Inner{
    InheritInner(WithInner wi){
        wi.super(); //wi的父类是object
    }
    public static void main(String[] args){
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
}

 

当被继承的内部类只有非默认构造器时应该怎么办呢?

class WithInner{
    class Inner{
        public Inner(int i){
            System.out.println(i);
        }
    }
}
public class InheritInner extends WithInner.Inner{
    InheritInner(WithInner wi){
        int i=0;
        wi.super(i);//如代码所示,当被继承的构造器需要参数时,应把参数传递给这个super函数
    }
    public static void main(String[] args){
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
}    

 

学习转载至:

海子博客内部类:https://www.cnblogs.com/dolphin0520/p/3811445.html

内部类的继承:http://phpstudy.php.cn/b.php/109910.html

内部类详解:http://www.cnblogs.com/chenssy/p/3388487.html

 

2018-10-15

推荐阅读