Java内部类(成员内部类、静态内部类、方法内部类、匿名内部类)

内部类
内部类是定义在一个类内部进行其他类结构的嵌套的操作。
为什么存在内部类?
1.首先看下内部类和不用内部类实现相同功能的代码:
不用内部类

//////不用内部类
class Outter
{
    private String msg="pick";
    public String Getmsg()
    {
        return msg;
    }
    public void fun()//3
    {
        Inner in=new Inner(this);//4
        in.Print();
    }
}
class Inner
{
    private Outter out;
    public void Print()
    {
        System.out.println(out.Getmsg());
    }
    public Inner(Outter out)
    {
        this.out=out;
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter out=new Outter();//1
        out.fun();//2
    }
}

用内部类

/////用内部类
class Outter
{
    private String msg="pick";
    class Inner  
    {
        public void Print()
        {
            System.out.println(msg);  //可以发现内部类可以直接访问外部类属性
        }
    }
    //在外部类中定义一个方法,该方法负责产生内部类对象,并调用Print
    public void fun()
    {
        Inner in=new Inner();
        in.Print();
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter out=new Outter();
        out.fun();
    }
}

可以发现两种方法实现相同的功能,用或不用内部类代码复杂程度不同,直接原因是内部类可以直接访问外部类私有属性。
2.内部类可以模拟实现多继承:

///内部类可以实现多继承
class A
{
    private String name="pick";
    public String Getname()
    {
        return name;
    }
}
class B
{
    private int age=18;
    public int Getage()
    {
        return age;
    }
}

class C
{
    class ExtendA extends A   //ExtendA 继承A
    {
        public String Name()
        {
            return new A().Getname();  // 返回父类A的属性name
        }
    }
    class ExtendB extends B // ExtendB 继承B
    {
        public int Age()
        {
            return new B().Getage();//返回父类B的属性年龄
        }   
    }
    public String name()
    {
        return new ExtendA().Name();  //返回内部类的Name,相当于A的name
    }
    public int age()
    {
        return new ExtendB().Age(); //返回内部类的Age,相当于B的age
    }
    //C类现在既有A的属性name,也有B的属性age,模拟实现了多继承
}
public class Out
{
    public static void main(String[] args)
    {
        C c=new C();
        System.out.println(c.name()); //pick
        System.out.println(c.age());  //18 
    }
}

3.内部类是另外一种封装,内部类具有保护性,对外部其他类不可见:
《Java内部类(成员内部类、静态内部类、方法内部类、匿名内部类)》
在主类中无法直接访问或者创建内部类
所以内部类存在原因如下:

  • 内部类可以直接访问外部类的私有域(包括私有属性和私有方法)

  • 内部类是另外一种封装(保护性),对外部的其他类隐藏(心脏包在人身体内部)

  • 内部类可以实现Java单继承的局限。
    但是内部类也存在缺点:结构复杂。

创建内部类
在外部类内部创建内部类
内部类 内部类引用=new 内部类();
Inner in=new Inner( ); (可参考上文中不用内部类代码)

在外部类外部创建内部类

  • 在外部类外部创建非静态内部类

外部类.内部类 内部类引用 =new 外部类( ).new 内部类( );

Outter.Inner in =new Outter( ).new Inner( );

//在外部类外部创建非静态内部类
class Outter
{
    class Inner
    {
        public String name="pick";
        public void show()
        {
            System.out.println("hello day");
        }
        
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter.Inner in=new Outter().new Inner(); 
        System.out.println(in.name);  //pick
        in.show(); //hello day
    }
}
  • 在外部类外部创建静态内部类

外部类.内部类 内部类引用=new 外部类.内部类( );
Outter.Inner in=new Outter.Inner( );

//创建非静态内部类
class Outter
{
    static class Inner
    {
        public String name="pick";
        public void show()
        {
            System.out.println("hello day");
        }    
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter.Inner in=new Outter.Inner(); 
        System.out.println(in.name);  //pick
        in.show(); //hello day
    }
}

内部类与外部类的关系

  • 内部类是一个相对独立的个体,与外部类没有is-a关系;
  • 对于非静态内部类,内部类的创建需要依赖外部类对象,在外部类没有实例化前无法创建非静态内部类。
  • 内部类可以直接访问外部类的元素(包括私有域),但是外部类不可以直接访问内部类元素,需要通过内部类的引用间接访问。
    内部类对外部类的直接访问:
class Outter
{
    private String name;
    private int age;
    class Inner
    {
        public Inner()
        {
           Outter.this.name="pick"; //如果用this,必须先找到外部类
           age=18;
        }
        public void fun()
        {
            System.out.println(name);
        }
    }   
}
public class Out
{
    public static void main(String[] args)
    {
        Outter.Inner in=new Outter().new Inner();
        in.fun();
    }
}

外部类通过内部类的引用间接访问内部类元素:

//外部类访问内部类
class Outter
{
    class Inner
    {
        private String name;
        public void print()
        {
            System.out.println("Inner");
        }
    }
    public void show()
    {
        Inner in=new Inner();
        System.out.println(in.name);  //内部类的引用间接访问内部类元素
        //System.out.println(name);  //错误,不能直接访问
        in.print();
    }    
}

内部类的分类

成员内部类(类比成员方法)

  • 成员内部类不能存在任何static变量或方法,可以访问外部类的静态域;
  • 成员内部类依赖外部类,只有先创建外部类才能创建内部类;在编译完成之后会隐含的保存一个引用,该引用指向创建它的外部类;

静态内部类(类比静态方法)

  • 使用static修饰的内部类为静态内部类
  • 静态内部类没有指向外部类的引用,所以静态内部类的创建不需要依赖外部类,可以直接创建;
  • 静态内部类不可以使用任何外部类的非static域(包括属性与方法),可以使用外部类的static域,但是可以存在自己的成员变量
    静态内部类不可以访问外部成员变量,但是可以拥有成员变量;
    成员内部类不可以拥有静态变量,但可以访问外部静态变量;因为静态变量和对象无关,是在编译时加载类存在的。

方法内部类

////方法内部类
class Outter
{
    private int num=10;
    public void func(int tmp)  //该tmp是final声明,只是JDK8将形参变为隐式final声明
    {
        //方法内部类
        class Inner
        {
            public void show()
            {
                //++tmp; //不可以修改,tmp是final声明
                System.out.println(tmp);
                System.out.println(num); //方法内部类可以访问方法外的属性,但是方法外访问不了方法内部类属性
            }
        }
        new Inner().show();
    }
}
public class Out
{
    public static void main(String[] args)   
    {
        Outter out=new Outter();
        out.func(19);  //  19  10
    }
}
  • 方法内部类不允许使用访问权限修饰符,public/private/protected均不允许;
  • 方法内部类对外部完全隐藏,除了创建这个类的方法可以访问它以外,其他地方均不能访问;
  • 方法内部类如果想要使用方法形参,该形参必须使用final声明。(JDK8将形参变为隐式final声明)
    创建方法内部类 的方法形参是final声明,不可以修改:
    《Java内部类(成员内部类、静态内部类、方法内部类、匿名内部类)》

匿名内部类(lamdba表达式前身)
匿名内部类就是一个没有名字的方法内部类。因此特点与方法内部类完全一样,除此之外,还有两个自己的特点:

  • 匿名内部类必须继承一个抽象类或者实现一个接口;
  • 匿名内部类没有构造方法,因为它没有类名 。但是方法内部类有构造方法。
//////匿名内部类:是特殊的方法内部类
interface Myinterface  //声明一个接口
{
    void print();//抽象方法:没有方法体
}
class Outter
{
    private int num=5;
    public void func(int tmp)
    {
        //匿名内部类,匿名的实现了Myinterface接口
        new Myinterface()
        {
            public void print()
            {
                System.out.println("匿名实现Myinterface接口");      
                System.out.println(tmp); 
                System.out.println(num);    
            }
        }.print();
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter out=new Outter();
        out.func(10);  //  匿名实现Myinterface接口   10  5 
    }
}

注:如果发现类名称上出现了“.”,就是内部类。

    原文作者:sophia__yu
    原文地址: https://blog.csdn.net/sophia__yu/article/details/83239242
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞