内部类和外部类区别:
-
内部内可以比外部类多使用三个修饰符:private、protected、static-----外部类不可以使用这三个修饰符
-
非静态内部类不能拥有静态成员
非静态内部内:
当非静态内部类的方法访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果存在就使用该变量,如果不存在,则到该方法所在的内部类中查找是否存在该名字的成员变量,如果存在则使用该成员变量;如果不存在,则到内部类所在的外部类查找是否存在该名字的成员变量;如果存在则使用该成员变量,如果不存在,系统出现编译错误:提示找不到该变量。
- 非静态内部成员可以访问外部类的private成员,但是反之不可以。
- 非静态内部类的成员只在非静态内部类的范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类成员,则必须显示创建非静态内部类对象来调用访问其实例成员。
- 不允许在外部类的静态成员中直接使用非静态内部类。
- 、不允许在非静态内部类里定义静态成员。
public class Cow {
private double weight;
public Cow(){};
public Cow(double weighr) {
this.weight=weight;
}
//定义一个非静态内部类
private class CowLeg{
//非静态内部类的两个实例变量
private double length;
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
private String color;
//非静态内部类的两个重载构造器
public CowLeg(){}
public CowLeg(double length,String color){
this.length =length;
this.color=color;
}
public void info(){
System.out.println(color+"..."+length);
System.out.println(weight);
}
}
public void test(){
CowLeg c1=new CowLeg(1.12,"黑白相间");
c1.info();
}
public static void main(String[] args){
Cow cow=new Cow(378.9);
cow.test();
}
}
静态内部类
- 静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
- 外部类不能直接访问静态内部类成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可使用静态内部类对象作为调用者来访问静态内部类的实例成员
- Java允许在接口里定义内部类,接口里定义内部类默认使用public static修饰,接口内部类只能是静态内部类。
内部类使用总结
定义类的作用主要是定义变量、创建实例和作为父类被继承。
- 在外部类内使用内部类
在外部类内部使用内部类,可以直接通过内部类类名定义变量,通过new调用内部类构造器来创建实例,不可以在外部静态成员定义静态内部类。
- 在外部类以外使用非静态内部类
private修饰的内部类只能在外部类内部使用,对于其他访问控制符修饰的内部类,只能在访问控制符对应的访问权限内使用
- 省略访问控制符的内部类,只能被与外部类处于同一包中的其他类所访问
- 使用protected修饰的内部类,可被与外部类处于同一包中的其他类所访问,以及外部类的子类所访问
- 使用public 修饰的内部类,可以在任何地方被访问
- 在外部类以外使用静态内部类
匿名内部类
//匿名内部类
public class Demo1 {
interface Eat{
public void eat();
}
abstract class Cat{
public abstract void eat();
}
//继承式
public void print1(){
//Cat是抽象类,不可以new对象,但是{}表示实现
Cat cat=new Cat(){
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("eat:继承式匿名内部类");
}
};
cat.eat();
}
//接口式
public void print2(){
//Eat是接口,不能建立对象,但是{}表示方法的实现
Eat eat=new Eat(){
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("eat:接口式匿名内部类");
}
};
eat.eat();
}
//参数式(方法传入接口)
public void print3(Eat eat){
eat.eat();
}
public static void main(String[] args) {
Demo1 d=new Demo1();
d.print1();
d.print2();
//参数式匿名类
d.print3(new Eat(){
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("eat:参数式式匿名内部类");
}
});
}
}
只用匿名内部类的注意点:
- 不能有构造方法,只能有一个实例
- 不能定义任何静态成员、静态方法
- 不能是public、protected、private、static
- 一定是在new后面,用其隐含实现一个接口或一个类
- 匿名内部类为局部的,所以局部内部类的所有限制都对其 生效
局部内部类访问局部变量必须用final修饰,为什么?
当调用该方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期试一样的。当方法被调用时会入栈,方法结束后即弹栈,这个局部变量也会消失。如果局部内部类对象没有马上消失想用这个局部变量,已经无法使用,使用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,可以继续使用。
注意:在jdk1.8中取消了在局部内部类中使用的变量必须显示的使用final修饰符,编译器默认会为这个变量加上final
内部类的作用:接口解决了部分继承问题,内部类有效实现了多重继承
成员内部类、方法内部类、匿名内部类都依赖外部类对象,静态内部类不依赖外部类的对象。因此在项目中优先选择静态内部类。