内部类
可以将一个类的定义放在里另一个类的内部(所谓的内部类的概念只是出现在编译阶段,对于jvm层是没有内部类这个概念的)
内部类是可以访问外部类的私有字段和私有方法的
用处:
- 类的单继承问题,外部类不能再继承的类可以交给内部类继承
- 可以通过定义内部类来实现一个类私属于一个类,实现更好的封装性
- 代码优化:它需要更少的代码
分类:
- 静态内部类
- 非静态内部类(成员内部类、方法内部类、匿名内部类)
静态内部类
静态内部类的定义和普通的静态变量或者静态方法的定义方法是一样的:使用static关键字
- 只有静态内部类才能允许使用static关键字修饰class
- 当内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是内部类的成员。
- 不能使用外部类的非static成员变量或者方法
定义一个静态内部类:
public class StaticClassTest {
private static String name;
private int age;
public static class In{
// private int age;
public void sayHello(){
//--编译报错--
//外部类的非静态私有字段age在静态内部类中是不允许访问
//System.out.println("hello "+age);
System.out.println("hello "+name);
}
}
}
接口:
public interface OutInterface {
//嵌套类,在接口中定义的任何类都自动的是public和static的,因此这两个关键字都可以省略
class Inner {
public void print() {
System.out.println("print()");
}
}
}
In这个类是一个静态内部类:遵循一致的原则,只能访问外部类的静态成员
创建一个静态内部类的实例对象:
public static void main(String[] args) {
StaticClassTest.In innerClass=new StaticClassTest.In();
innerClass.sayHello();
}
使用场景: 对于和外部类联系紧密但是并不依赖于外部类实例的情况下,可以考虑定义成静态内部类
静态内部类与普通内部类的区别:
- 普通内部类只能包含非静态变量、非静态方法、非嵌套类。
- 静态内部类可以包含静态和非静态变量、静态和非静态方法、静态和普通内部类。
成员内部类
成员内部类可以拥有 private、protected、public及包的访问权限:
如果成员内部类分别用以下权限修饰符修饰,结果如下:
(1) private,则只能在外部类的内部访问;
(2) public,任何地方都能访问;
(3) protected,则只能在同一个包下或者继承外部类的情况下访问;
(4) 默认,只能在同一个包下访问。
外部类只能被public和protected两种权限修饰符进行修饰
- 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)
- 当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员
- 如果要访问外部类的同名成员,需要以特定的形式进行访问
使用场景: 对于那种要高度依赖外部类实例的情况下,可以选择将内部类定义成成员内部类
定义成员内部类:
public class Out {
private String name;
public String common3 = "outer.common3";
public void showName(){
System.out.println("name:"+name);
}
//成员内部类可以直接访问外部类的成员字段和成员方法
public class In{
public String common3 = "inner.common3";
public void sayHello(){
System.out.println(name);
//外部类.this.成员变量
//外部类.this.成员方法
Out.this.showName();
// 如果要访问外部类的同名成员,需要以下面的形式进行访问
System.out.println(Out.this.common3);
}
}
// 而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:
Out getInnerInstance() {
return new In();
}
}
创建内部类实例:
public static void main(String [] args){
//方式一:
Out out = new Out();
out.setName("123")
Out.In in = out.new In();
in.sayHello();
//方式二:
In in2=out.getgetInnerInstance();
}
成员内部类是关联着一个具体的外部类实例的,所以成员内部类的实例创建必然是由外部类实例来创建的
- 成员内部类的实例创建需要关联外部类实例对象
方法内部类
定义在一个方法内部的类
public class Out {
private String name;
public void sayHello(){
class In{
public void showName(){
System.out.println("my name is : "+name);
}
}
In in = new In();
in.showName();
}
}
方法内部类的生命周期不超过包含它的方法的生命周期----->方法内部类只能在方法中使用
- 所以在声明的时候,任何的访问修饰符都是没有意义的,于是不允许使用任何的访问修饰符修饰方法内部类
对于方法内部类而言,只能在方法内部new对象
实现原理:
- 方法内部类是定义在具体方法的内部的,所以该类除了可以通过传入的外部实例访问外部类中的字段和方法,对于包含它的方法中被传入的参数也会随着外部类实例一起初始化给内部类。
使用场景: 一般只有在需要高度封装的时候才会将类定义成方法内部类
匿名内部类
匿名内部类就是没有名字的内部类,在定义完成同时,也创建好了实例,常常和new关键字紧密结合
- 匿名内部类不能有访问权限修饰符和static修饰符的
- 匿名内部类是唯一一种没有构造器的类,使用范围非常有限,大部分匿名内部类用于接口回调
- 匿名内部类在编译的时候由系统自动起名为 Outter$1.class。
它也不局限于类,也可以是接口,可以出现在任何位置
//首先定义一个普通类
public class Out {
private String name;
public void sayHello(){
System.out.println("my name is :" + name);
}
}
//定义和使用一个匿名内部类
public static void main(String [] args){
Out out = new Out(){
@Override
public void sayHello(){
System.out.println("my name is cyy");
}
public void showName(){
System.out.println("hello single");
}
};
out.sayHello();
Runnable myRunner = new Runnable() {
@Override
public void run() {
// do sth
}
};
}
- 匿名内部类都是通过继承一个父类,重写或者重新声明一些成员来实现一个匿名内部类的定义
匿名内部类的主要特点在于,没有名字,对象只能被使用一次,可以出现在任意位置
使用场景:
对于一些对代码简洁度有所要求的情况下,可首选匿名内部类
java-就是要让你学会内部类:https://mp.weixin.qq.com/s/lFNSU0qIpJm08mpftOsQrw
【内部类】四种内部类:https://mp.weixin.qq.com/s/jRqiyxLEq-AYYgrhBjNnng