1.为什么需要使用内部类
大部分的时候,类被定义成一个独立的程序单元。内部类就是把一个类放在另一个类的内部,包含内部类的类也被称为外部类。
内部类主要有以下作用:
a.内部类提供更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类.
b.内部类成员可以直接访问外部类私有数据,因为内部类被当做其外部类成员,同一个类的成员之间可以相互访问.但外部类不能访问内部类的实现细节,例如内部类的成员变量.
c.匿名内部类适合用于创建那些仅需要使用一次的类
内部类和外部类主要有两种区别
a.内部类比外部类多三个修饰符,private 、protected、static
b.非静态内部类不能拥有静态成员变量
2.非静态内部类
package com.liqiang.demo5;
public class InnerNoStatic {
private class InnerClass{
private int age = 1;
public void show(){
System.out.println(age);
}
}
}
非静态内部类不能含有静态成员
2.静态内部类
如果使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。
静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员。
package innerclass;
public class StaticInnerClassTest {
private int prop1 = 5;
private static int prop2 = 5;
static class StaticInnerClass{
private static int age;
public void accessOuterProp() {
}
}
}
3.使用内部类
分三种情况讨论内部类的用法
1.在外部类内部使用内部类:
在外部类内部使用内部类和平常使用普通的类没有什么区别,唯一的区别就是不要在外部类的静态成员(包括静态方法和静态初始块)中使用非静态内部类。
2.在外部类以外使用非静态内部类
如果希望在外部类以外的地方访问内部类(包括静态和非静态两种),则内部类不能使用private访问控制权限。
a.省略了访问控制符的内部类,只能被外部类或处于同一个包中的其他类访问。
b.使用了protected修饰的内部类,可被与外部类处于同一包中的其他类和外部类的子类所访问。
c.public修饰的内部类,可以在任何地方被访问。
变量语法的格式如下:
OuterClass.InnerClass varName
由于非静态内部类的对象必须寄生在外部类的对象里,因此创建非静态内部类对象之前,必须先创建其外部类对象。
OuterInstance.new InnerConstructor()
3.在外部类以外使用静态内部类
因为静态内部类是外部类类相关的,因此创建静态内部类对象是无需创建外部类对象。在外部类以外的地方创建静态内部类实例的如法如下:
new OuterClass.InnerConstructor();
4.Java8改进的匿名内部类
匿名内部类适合创建那些要一次使用的类
定义匿名内部类的语法如下:
new 实现接口() | 父类构造器(实参列表)
{
//匿名内部类实体成分
}
从上面定义可以看出匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类和继承一个接口。
匿名内部类还有如下两条规则:
1.匿名内部类不能是抽象类,这个就不说了为什么了。。。
2.匿名内部类不能定义构造器。由于匿名内部类没名字啊,哥哥姐姐们,所以肯定不能有构造器啊。
如下是一个匿名内部类的简单用法:
package innerclass;
interface Product{
public double getPrice();
public String getName();
}
public class AnnotmousTest {
public void test(Product p) {
System.out.println("buy a :" + p.getName() +" cost " + p.getPrice());
}
public static void main(String[] args) {
AnnotmousTest ta = new AnnotmousTest();
ta.test(new Product() {
@Override
public double getPrice() {
// TODO Auto-generated method stub
return 567;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return "hahaa";
}
});
}
}
当创建匿名内部类时就必须实现接口或抽象父类里的所有抽象方法。
在Java8之前,Java要求被局部内部类,匿名内部类访问的局部变量必须使用final修饰,从Java8这个就被取消了,如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了final.
如下
package com.liqiang.demo5;
interface A{
void test();
}
public class InnerNoStatic {
public static void main(String[] args){
int age = 8;
A a = new A() {
@Override
public void test() {
// TODO Auto-generated method stub
System.out.println(age);
}
};
a.test();
//加了这个会发生编译错误
//age = 2;
}
}
5.lambda表达式待续