看到自己去年转载的一篇关于内部类的文章,把自己看出好多疑问……
不如重新跟着学习一下……
内部类
内部类,顾名思义,就是在一个类的内部定义的类。
优点:
- 内部类与外部类可以方便的访问彼此的私有域(包括私有方法、私有属性)
- 内部类是另外一种封装,对外部的其他类隐藏
- 方便编写事件驱动程序和线程代码
- 可以实现多重继承
Java的类是单继承的,只能有一个父类。每个内部类都能独立的继承一个类,而外部类的继承,对于内部类没有影响。接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
多重继承小例子:
class A {
private String name = "A类的私有域";
public String getName() {
return name;
}
}
class B {
private int age = 20;
public int getAge() {
return age;
}
}
class Outter {
private class InnerClassA extends A {
public String name() {
return super.getName();
}
}
private class InnerClassB extends B {
public int age() {
return super.getAge();
}
}
public String name() {
return new InnerClassA().name();
}
public int age() {
return new InnerClassB().age();
}
}
public class Test2 {
public static void main(String[] args) {
Outter outter = new Outter();
System.out.println(outter.name());//A类的私有域
System.out.println(outter.age());//20
}
}
缺点:
- 使代码结构复杂
1.成员内部类
成员内部类是最普通的内部类,就是类的成员。
特点:
- 作为外部类的一个成员存在,与外部类的属性、方法并列,因此只有先创建了外部类,才能创建成员内部类
- 成员内部类像类的成员一样,可以拥有多种权限修饰
- 成员内部类持有外部类的引用
- 成员内部类中不能定义static变量和方法
关于成员内部类不能有static变量,感觉上就是有二义性。
- 这个成员内部类的每个实例,都有着一致的静态变量。(本题的争议点,大家觉得这样毫无问题,可是Java确实会报一个编译错误)
- 持有相同外部类实例引用的内部类实例,有着一致的静态变量。
这两种理解都有其合理性,这就要看编译器了。事实上,这种限制是仅仅存在于java编译器,就可以理解为是一种规定……
使用方法一:
/**
* @author zj
* @date 2020/5/8
*/
class Outer {
private int a = 0;
public static int b =1;
public Outer() {
}
class Inner { //内部类
int a = 4;
public void fun() {
//当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员
System.out.println(a); //——4
//如果要访问外部类的同名成员,需要以下面的形式进行访问
System.out.println(Outer.this.a);//外部类的private成员——0
System.out.println(b); //外部类的静态成员
}
}
}
public class InnerClassTest {
public static void main(String[] args){
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.fun();
}
}
使用方法二:
一般如果成员内部类的构造函数无参的话,推荐使用使用getxxx()。
/**
* @author zj
* @date 2020/5/8
*/
class Outer {
private int a = 0;
public static int b =1;
public Outer() {
}
public Inner getInnerInstance(){
return new Inner();
}
class Inner { //内部类
public void fun() {
System.out.println(a); //外部类的private成员
System.out.println(b); //外部类的静态成员
}
}
}
public class InnerClassTest {
public static void main(String[] args){
Outer outer = new Outer();
//Outer.Inner inner = outer.new Inner();
Outer.Inner inner = outer.getInnerInstance();
inner.fun();
}
}
2.静态内部类
静态内部类就是使用static修饰的内部类。类似于类的静态成员属性。
静态内部类和非静态内部类之间存在一个最大的区别,非静态内部类在编译完成之后会隐含的保存着一个引用,该引用是指向创建它的外部类,但是静态类没有。
因此:
- 静态内部类的创建不需要依赖外部类可以直接创建。
- 静态内部类不可以使用任何外部类的非static属性和方法,但可以存在自己的成员变量。
使用方法:
/**
* @author zj
* @date 2020/5/8
*/
class Outer {
private int a = 0;
public static int b =1;
public Outer() {
}
static class Inner { //内部类
int c = 2;
public void fun() {
//System.out.println(a); //非static会报错
System.out.println(new Outer().a);//这样就不会报错——0
System.out.println(b); //外部类的静态成员
System.out.println(c); //内部类的变量
}
}
}
public class InnerClassTest {
public static void main(String[] args){
Outer.Inner inner = new Outer.Inner();//无需创建外部类
inner.fun();
}
}
3.局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,感觉类似一个局部变量。
- 它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内
- 根据情况决定持有外部类对象引用
- 不能使用private,protected,public,static修饰符,不能包含静态成员
- 方法内部类对外部完全隐藏,除了创建这个类的方法可以访问它以外,其他地方均不能访问
- 方法内部类要想使用方法形参,该形参必须使用final声明(JDK8形参变为隐式final声明,原因参考下面的小例子)
使用方法:
/**
* @author zj
* @date 2020/5/8
*/
class Outer {
private int a = 0;
public static int b =1;
public Outer() {
}
public void outFun(){
class Inner{ //方法中定义内部类
int c = 2;
public void fun() {
System.out.println(a);
System.out.println(b); //外部类的静态成员
System.out.println(c); //内部类的变量
}
}
//局部内部类在方法里面创建
new Inner().fun();
}
}
public class InnerClassTest {
public static void main(String[] args){
Outer outer = new Outer();
outer.outFun();
}
}
方法形参例子:
在下面这个例子中,外部类的方法中有个参数temp,如果它不是final的话,那么在方法中的内部类对它进行改变之后,我们希望外面的这个temp的值也是改变之后的结果。但由于Java传参是值传递,所以外面的temp的值没有改变。所以为了保持参数的一致性,就规定使用final来保证形参的不可改变。
/**
* @author zj
* @date 2020/5/8
*/
class Outer {
private int a = 0;
public static int b =1;
public Outer() {
}
//public void outFun(final int temp){//final可以省略,隐式final声明
public void outFun(int temp){
class Inner{ //方法中定义内部类
public void fun() {
//temp++;//会报错,因为temp是隐式final声明,就算没用final也是final,只能用不能改
System.out.println(temp);
}
}
//局部内部类在方法里面创建
new Inner().fun();
}
}
public class InnerClassTest {
public static void main(String[] args){
Outer outer = new Outer();
int temp = 1;
outer.outFun(temp);
}
}
4.匿名内部类
匿名内部类就是一个没有名字的内部类。
这是Java为了方便我们编写程序而设计的一个机制,因为有时候有的内部类只需要创建一个它的对象就可以了,以后再不会用到这个类,这时候使用匿名内部类就比较合适。一般使用匿名内部类的方法来编写事件监听代码。
匿名内部类在编译的时候由系统自动起名为Outter$1.class,其它为Outter$Inner.class。
- 创建的匿名类,默认继承或实现new后面的类型,匿名内部类必须继承一个抽象类或者实现一个接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
- 匿名内部类也是不能有访问修饰符和static修饰符的。
- 匿名内部类没有类名,因此没有构造方法。
- 要想使用方法形参,该形参必须使用final声明(JDK8形参变为隐式final声明)
使用方法:
/**
* @author zj
* @date 2020/5/8
*/
interface MyInterface{
void fun();
}
class Outer {
private int a = 0;
public static int b =1;
public Outer() {
}
public void outFun(int temp){
new MyInterface(){
@Override
public void fun() {
System.out.println("匿名实现MyInterface接口");
System.out.println(temp);
}
}.fun();//注意分号
}
}
public class InnerClassTest {
public static void main(String[] args){
Outer outer = new Outer();
outer.outFun(1);
}
}