1.什么是内部类?
在类中定义的类:在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
内部类包括:
- 1.成员内部类:类中定义的成员类
- 2.静态内部类:类中定义的静态成员类
- 3.局部内部类:类的成员方法中定义的类
- 4.匿名内部类:类实例化时,直接定义的类。定义与使用同步;
2.存在意义
java中的内部类和接口加在一起,可以的解决常java中存在的一个问题——没有多继承。
通过内部类继承其他类,从而实现多继承?接口不是也可以实现么???
为什么需要内部类
1)现象:
典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外部类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。
2)使用内部类最吸引人的原因是:
-
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
-
如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
内部类的优点:
- 内部类与外部类可以方便的访问彼此的私有域(包括私有方法、私有属性)。
- 内部类是另外一种封装,对外部的其他类隐藏。
- 内部类可以实现java的单继承局限。
内部类的缺点:
- 结构复杂
3.特性
1.成员内部类
1)格式:
【访问修饰符】 class Demo4{五大成员(不包括静态资源)}
2)成员特性:
-
1)成员内部类可以采用任意一个访问修饰符修饰
-
2)内部类的五大成员成员,但不能有静态的资源
因为,加载时机不一样: 可以把内部类看为类的一个特殊方法,非静态方法[即内部类],在静态成员创建之后,其被调用[被new]时才会被创建。 -
3)成员内部类是依附外部类的,只有创建了外部类才能创建内部类
3)访问机制:
① 内部类访问外部类的资源
全部内容都是可以直接访问
② 外部类访问内部类的资源
创建对象进行访问
③ 外部其他类访问内部类
创建对象进行访问:
Demo3 d3=new Demo3(); //外部类
Demo3.Demo4 d4=d3.new Demo4(); //内部类
④ 内部类访问外部其他类
直接访问
4)重名问题:
- ①内部类和外部类具有重名的成员:就近原则访问
- ②外部类类名.this.成员
例子:Demo3.this.name
public class A{
private int s = 111;
public class B {
private int s = 222;
public void mb(int s) {
System.out.println(s); // 局部变量s
System.out.println(this.s); // 内部类对象的属性s
System.out.println(A.this.s); // 外层类对象属性s
}
}
public static void main(String args[]){
A a = new A(); //实例化外部类
A.B b = a.new B(); //内部类
b.mb(333);
}
}
5)注意:
内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。
对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。
6)两种成员内部类的使用方式:
- 1)通过外部类的成员方法调用内部类的成员
class A {
private int s;
public class B{
public void mb() {
s = 100;
System.out.println("在内部类B中s=" + s);
}
}
public void ma() {
B i = new B();
i.mb();
}
}
public class Test {
public static void main(String args[]){
A o = new A();
o.ma();
}
}
- 2)通过-外部类实例化后,再调用外部对象的内部类的构造方法进行实例化
public class A{
private int s = 111;
public class B {
private int s = 222;
public void mb(int s) {
System.out.println(s); // 局部变量s
System.out.println(this.s); // 内部类对象的属性s
System.out.println(A.this.s); // 外层类对象属性s
}
}
public static void main(String args[]){
A a = new A();
A.B b = a.new B();
b.mb(333);
}
}
2.静态内部类
???静态内部类中都是静态成员么?【其内部成员的内存运行方式】
1)格式:
【访问修饰符】 static class Demo5{五大成员(包括静态资源)}
2)成员特性:
-
1)静态内部类可以采用任意一个访问修饰符修饰
-
2)内部类的五大成员成员,包括静态的资源
- 可以把内部类看为类的一个特殊静态方法,在类加载时即加载。
-
3)静态内部类和非静态内部类之间存在一个最大的区别:区别就在于静态内部类没有了指向外部的引用;(还有就是能使用外部类的静态成员)
-
4)非静态内部类在编译完成之后会隐含的保存着一个引用,该引用是指向创建它的外围类,但是静态类没有。没有这个引用就意味着:
1.静态内部类的创建不需要依赖外部类可以直接创建。对比:在成员内部类中访问外部类中与内部类同名的实例变量用:外部类名.this.变量名
2.静态内部类不可以使用任何外部类的非static类(包括属性和方法),但可以存在自己的成员变量。
2)访问机制:
① 内部类访问外部类的资源
普通成员 :创建对象访问
静态成员:直接访问(创建对象访问)
② 外部类访问内部类的资源
普通成员 :创建对象访问
静态成员:直接访问(创建对象访问)
③ 外部其他类访问内部类
创建对象进行访问
Demo3.Demo5 d35=new Demo3.Demo5();
④ 内部类访问外部其他类
直接访问
3)重名问题:
1)外部类中资源是非静态的,不会发生重名问题
2)外部类中的静态资源和内部类中的资源重名,访问外部类的资源 :类名.资源
3.局部内部类
只能使用方法中的局部常量,因为局部内部类对象和局部变量的生命周期不一样[前者可能更长]
特点:
-
1)不能采用访问修饰符,方法内部类不允许使用访问权限修饰符(public、private、protected)均不允许。;
-
2)方法内部类对外部完全隐藏。除了创建这个类的方法可以访问它以外,其他地方均不能访问 (换句话说其他方法或者类都不知道有这个类的存在)。
-
3)方法内部类如果想要使用方法形参,该形参必须使用final声明(JDK8形参变为隐式final声明)
-
4)可以有五大成员,但不能有静态成员;
-
5)可以使用多态的形式调用;
访问机制:
① 内部类访问外部类的资源
直接访问
①补充:内部类访问外部类的局部变量
可以直接访问,该局部变量默认变为常量 (内部类的对象的生命周期长与局部变量)
② 外部类访问内部类的资源
由于局部内部类只能在当前局部创建对象,在外界是用不了
③ 外部其他类访问内部类
用不了
④ 内部类访问外部其他类
直接访问
重名问题:
外部类和局部内部类出现资源重名问题
Demo3.this.age \\外部类Demo3
\\类中
public Object method1(){
int a=9;
//局部内部类
class Demo6{
private String email;
private int age=5;
private int a=8;
{}
public void method6(){
System.out.println(a);
}
public Demo6(){
}
}
Demo6 d6=new Demo6();
d6.method6();
return new Demo6();
}
JDK8关于final关键字的改变
在java7及以前的版本中:需要显式的声明为final。
java8中可以省略final的声明。
- 但如果之后又出现赋值语句,则不是常量;
案例:
public void myMethod(){
int num = 10;//方法内的局部变量
//局部内部类
class A implements B{
//局部内部类中的方法
public void method1(){
System.out.println(num); //可以使用:因为默认是自定义常量
//num = 9; //如有这句——num不会默认为常量,上一句编译出错。
}
}
A a = new A();
return A;
//返回值-对象,一般使用多态的方式复制给父类或实现接口的引用,固其使用存在局限性
}
4.匿名内部类
特性:
- 1)没有类名,定义和使用是一起的;
- 2)匿名内部类应用在对抽象类和接口的实现上,必须继承一个抽象类或者实现一个接口;
- 3)匿名内部类没有类名,因此没有构造方法。
案例1:
Super1 s = new Super1(){
private int age;
//重写了Super1中fun1方法
public void fun1(){
System.out.println("fun2");
}
}
访问机制:
① 内部类访问外部类的资源
直接访问
①补充:内部类访问外部类的局部变量
可以直接访问,该局部变量默认变为常量 (内部类的对象的生命周期长于局部变量)
② 外部类访问内部类的资源[重写呢?]
由于匿名内部类在定义时就被实例化了,在外界是用不了(匿名内部类中存在重写)
③ 外部其他类访问内部类
用不了
④ 内部类访问外部其他类
直接访问
案例2:
interface Caculate {
public void caculate();
}
class Phone {
public void testWork(Caculate c) {
c.caculate();
}
}
public class Test1 {
/*
* 计算器接口具有work方法,功能是运算;
* 有一个手机类Cellphone,定义方法testWork测试计算功能,
调用计算接口的work方法,
要求调用CellPhone对象 的testWork方法,使用上 匿名内部类
*/
public static void main(String[] args) {
//1.使用接口多态形式,使用匿名内部类
Phone p1 = new Phone();
Caculate c = new Caculate() {
@Override
public void caculate() {
System.out.println("手机p1计算器");
}
};
p1.testWork(c);
//2.直接将匿名内部类作为参数传递
Phone p2 = new Phone();
p2.testWork(new Caculate() {
@Override
public void caculate() {
// TODO Auto-generated method stub
System.out.println("手机p2计算器");
}
});
}
}