内部类
内部类就是定义在类内部的类,可以 是成员内部类(类的第五种成员,分为静态内部类和非静态内部类),也可以定义在方法内部(局部内部类)。宿主类不能访问内部类的成员。可以通过”静态内部类名.静态内部类静态成员“和”内部类对象.内部类成员“来访问
非静态内部类
没有static修饰的成员内部类就是非静态内部类。非静态内部类不有静态成员。
访问权限的思考?
类的上级是包,包的上级是工程,所以类的访问控制修饰符有默认不写和public两种。类的成员如内部类,上级是类,再上级是包,再再上级是工程,所以类的成员的访问控制权限有private,默认不写和protected(子类可访问)。
示例代码及内存情况
//注意下面示范了宿主类成员变量,内部类成员变量和内部类局部变量同名的情况
class OutClass{
private String prop = "外部类成员变量";
private class InClass{
private String prop = "内部类成员变量";
public void info(){
String prop = "局部变量";
System.out.println(prop);//输出局部变量
System.out.println(this.prop);//输出内部类成员变量
System.out.println(OutClass.this.prop);//输出外部类成员变量
}
}
public void test(){
InClass in = new InClass();
in.info();
}
}
class Hello{
public static void main(String[] args){
OutClass out = new OutClass();
out.test();
}
}
编译后生成了这几个字节码文件:
静态内部类
有static修饰的成员内部类是静态内部类。静态内部类可包好静态成员和非静态成员。
接口里可以定义内部类,默认使用public static修饰。接口里也可以定义内部接口(几乎不用),系统默认使用public static修饰。
使用内部类示例代码
//在外部使用内部类
class OutClass{
class InClass{
public InClass(String msg){
System.out.println(msg);
}
}
}
class Hello{
public static void main(String[] args){
new OutClass().new InClass("在宿主类的外部使用内部类");
}
}
//继承宿主类的内部类。要使用非静态内部类,那首先得有宿主类的实例。
class OutClass{
class InClass{
public InClass(String msg){
System.out.println(msg);
}
}
}
class Hello extends OutClass.InClass{
public Hello(OutClass out){
out.super("hello");//super代表的是OutClass类的内部类InClass类
}
public static void main(String[] args){
new Hello(new OutClass());
}
}
//使用静态内部类
class OutClass{
static class InClass{
public InClass(String msg){
System.out.println(msg);
}
}
}
class Hello{
public static void main(String[] args){
new OutClass.InClass("hello");
}
}
子类重写父类的内部类可以吗??
假设Father类的子类是Son类,Father类的内部类是In类,假设可以重写,那么重写后Son类的内部类为Father.Son.In,而父类的内部类是Father.In,显然这里两个名字是不一样的,名字都不一样,显然不可能重写。
局部内部类
定义在方法内部的类是局部内部类。和局部变量同级别,只能在方法内部使用,显然不能用访问控制符和static修饰,因为没意义。
下面是示例代码,笔者故意把A的成员变量x设置成了private,在A外面访问x很随意啊!!
class Hello{
public static void main(String[] args){
class A{
private int x = 1;
}
A a = new A();
a.x = 666;
System.out.println(a.x);
}
}
匿名内部类
new 实现接口() | 父类构造器(实参列表){
//匿名内部类的实体部分
}
匿名内部类是定义在类内部的没有名字的类。由上面的定义方式,我们就知道只能实现一个接口或继承一个父类。创建匿名内部类的时候就会立即创建一个实例,定义随即消失。由此也可知道匿名内部类绝不可是抽象类。另外,匿名内部类不能定义构造器,因为匿名内部类没有名字,自然不可能由构造器,但可以定义初始化块。
interface A{
public abstract String getName();
}
class Hello{
public void test(A a){
System.out.println(a.getName());
}
public static void main(String[] args){
new Hello().test(new A(){
public String getName(){
return "hello";
}
});
}
}
上面代码是匿名内部类的实例,如果不使用匿名内部类的话,可以改写代码如下:
interface A{
public abstract String getName();
}
class B implements A{
public String getName(){
return "hello";
}
}
class Hello{
public void test(A a){
System.out.println(a.getName());
}
public static void main(String[] args){
new Hello().test(new B());
}
}
abstract class A{
private String name;
public abstract String getSex();
public A(){}
public A(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
class Hello{
public void test(A a){
System.out.println(a.getName()+" "+a.getSex());
}
public static void main(String[] args){
Hello h = new Hello();
h.test(new A(){
{
System.out.println("我是匿名内部类的初始化块");
}
public String getSex(){
return "female";
}
//重写父类的方法
public String getName(){
return "Marry";
}
});
h.test(new A("Jack"){
public String getSex(){
return "male";
}
});
}
}
局部内部类、匿名内部类访问的局部变量必须是final修饰的:
interface A{
public abstract void test();
}
class Hello{
public static void main(String[] args){
int x = 2;
A a = new A(){
public void test(){
//Java8开始,匿名内部类、局部内部类允许访问非final的局部变量,也就是说,
//如果访问了,那么那个变量即使没有final修饰,也会自动变为是final修饰的变量
//Java8之前这是不允许的,编译过不了
System.out.println("x");
}
};
a.test();
}
}