Java内部类
1、概念
内部类是指在一个外部类的内部再定义一个类。
2、特征
- 1、内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
- 2、内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。
- 3、内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量。(这与类中的静态成员方法只能访问静态成员是类似的)。
3、作用
- 1、内部类可以很好的实现隐藏,一般的非内部类,是不允许有private和protected访问权限,但内部类可以。
- 2、内部类拥有外围类的所有元素的访问权限。
- 3、可以实现多重继承。
- 4、可以避免修改接口而实现同一个类中两种同名方法的调用。
4、分类
Java内部类分为: 实例内部类、静态内部类、匿名内部类、局部内部类。
4.1、实例内部类
实例内部类,直接定义在类中。就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取。
要注意的是,实例内部类不能含有static的变量和方法。因为实例内部类需要先创建了外部类,才能创建它自己的。
实例内部类可用访问权限修饰符public,protected,friendly(默认),private。
class Car{
class Windows{//实例内部类
private String name;
private int high;
}
private Windows windows;
public Car(){
windows = new Windows();
}
}
class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); //创建成员内部类的对象,左边的Outer可以不要
inner.print("调用内部类的方法");
}
public class Inner {
public void print(String str) {
System.out.println(str);
}
}
}
4.2、静态内部类
与实例内部类定义的唯一区别是前面加了一个static的修饰符。
静态内部类,不需要内部类对象和外部类对象之间的联系。
class A{
static class B{ //静态内部类
private String name;
private int age;
public B(){
this.name = name;
}
}
private String name;
private int age;
private B b;
public A(){
this.name = name;
b = new B();
}
}
class Outer {
static class Inner{
static class In{
}
public void print(String str) {
System.out.println(str);
}
}
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner(); //创建静态内部类的对象
inner.print("调用内部类的方法");
}
}
静态内部类和实例内部类的区别:
-
实例内部类不能有static数据和static属性,也不能包含静态内部类,但静态内部类可以。
-
创建内部类对象时静态内部类必须用Outer.Inner,实例内部类可以用Outer.Inner,也可以用Inner。
-
实例内部类和静态内部类的区别(实例内部类相比静态内部类的开销在哪里?)
- 实例内部类包含两个this (指向当前对象,外部类对象的this)
- 静态内部类包含一个this (指向当前对象)
-
实例内部类,静态内部类使用上对象的生成方式:
-
实例内部类对象:OutClass.InnerClass i = new OutClass().new InnerClass();
-
静态内部类对象:OutClass.InnerClass i = new OutClass.InnerClass();
-
4.3、匿名内部类
有时候为了免去给内部类命名,便倾向于使用匿名内部类,因为它没有名字。
匿名内部类是不能加访问修饰符的。即它的访问权限修饰符只能是friendly(默认的)。
要注意的是,new 匿名内部类,这个类是要先定义的。
匿名内部类实际上就是继承一个已经存在的类,但是省略自身类的名字。
当所在的方法的形参需要被内部类里面使用时,该形参必须为final。
interface Interface {
void show();
}
abstract class A{
abstract void show();
}
class Test{ //匿名内部类
public static void main(String[] args) {
A a = new A(){
@Override
void show() {
}
};
Interface i = new Interface() {
@Override
public void show() {
}
};
}
}
class Outer {
public Inner getInner(final int i,int j) {
return new Inner(){
int k;
{
k=i;//如果是k=j,会报错
}
};
}
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner(2014,11); //创建指向匿名内部类的父类对象引用
}
public class Inner {
public void print(String str) {
System.out.println(str);
}
}
}
4.4、局部内部类
局部内部类,是指内部类定义在方法和作用域内。
局部内部类只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
局部内部类可用访问权限修饰符只有friendly(默认)。
定义在方法内:
class Outer {
public In play(){
class Inner extends In{
public void print(String str) {
System.out.println(str);
}
}
return new Inner();
}
public static void main(String[] args) {
Outer outer = new Outer();
In inner = outer.play(); //创建指向局部内部类的基类对象引用,只有这样才可以在局部内部类的作用于外使用局部内部类
inner.print("调用内部类的方法");
}
}
class In{
public void print(String str) {
}
}
定义在作用域里:
class Outer {
public In play(int i){
if(i>5){
class Inner extends In{
public void print(String str) {
System.out.println(str);
}
}
return new Inner();
}
return null;
}
public static void main(String[] args) {
Outer outer = new Outer();
In inner = outer.play(2014); //创建指向局部内部类的基类对象引用,只有这样才可以在局部内部类的作用于外使用局部内部类
inner.print("调用内部类的方法");
}
}
class In{
public void print(String str) {
}
}
5、访问修饰符
5.1、修饰成员
public、默认、protected、private -> 修饰成员
protected <=> 默认 包访问权限
继承:子类和父类定义在不同包下,子类可以访问父类用protected修饰的属性和方法
5.2、修饰类:
修饰外部类:public 默认
修饰内部类:四种访问修饰符都行