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单继承的局限。
但是内部类也存在缺点:结构复杂。
创建内部类
在外部类内部创建内部类
内部类 内部类引用=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声明,不可以修改:
匿名内部类(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
}
}
注:如果发现类名称上出现了“.”,就是内部类。