在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部(方法)内部类、匿名内部类和静态内部类。
一.成员内部类:
1.成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和static静态成员)。
class Circle {
private double radius = 0;
public static int count =1;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //成员内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
System.out.println(count); //外部类的静态成员
}
}
}
2.当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况访问的是成员内部类的成员。如果要访问外部类的同名成员,需要加上“外部类.this.”前缀进行访问:
外部类.this.成员变量
外部类.this.成员方法
3.在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。
class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe(); //先创建成员内部类的对象,再进行访问
}
private Draw getDrawInstance() { //getDrawInstance方法创建成员内部类对象
return new Draw();
}
class Draw { //成员内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
}
}
}
4.在别的类中创建指定成员内部类对象的方式:成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。
//Test类
public class Test {
public static void main(String[] args) {
//创建内部类对象第一种方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner(); //必须通过Outter对象来创建
//创建内部类对象第二种方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
//不是Test类,是内部类的外部类
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
5.内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。比如上面的例子,
- 如果成员内部类Inner用private修饰,则只能在外部类的内部访问,
- 如果成员内部类Inner用public修饰,则任何地方都能访问;
- 如果成员内部类Inner用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;
- 如果成员内部类Inner是默认访问权限default ,则只能在当前同一个包下访问。
二、局部(方法)内部类
局部(方法)内部类是定义在一个方法或者一个作用域里面的类,类似局部变量一样,是不能有public、protected、private以及static修饰符的。它和成员内部类的区别在于局部内部类的访问范围仅限于方法内或者该作用域内。
public class PartialDemo {
String name = "王五";
static int age = 10;
public static void show() {
System.out.println("掉用外部类中的show方法");
}
public void printf() {
System.out.println("调用外部类中的打印方法");
}
public void demo() {
//内部类所在方法的属性
String name = "张三";
double height = 1.8;
//编写在方法的内部的类称之为局部(方法)内部类
//局部内部类不可使用权限修饰符 静态修饰符进行修饰 同局部变量相同
//局部内部类与局部变量使用范围一样 在此方法内部
//局部内部类可以直接访问方法中的属性 重名时使用参数传递完成访问
//局部内部类 可以访问方法外部类中属性和方法 :外部类.this.属性
class Inner{
String name = "李四";
public void showInner(String name) {
show();
printf();//不需要this,直接访问外部类的方法
System.out.println(age);//外部类的age
System.out.println(height);//局部内部类所在方法的age
System.out.println("这是:"+PartialDemo.this.name);//外部类的name
System.out.println("这是:"+name);//局部内部类所在的方法的形参name
System.out.println("这是:"+this.name);//局部内部类的name
}
}
//局部内部类 创建对象 要在方法内部 局部内部类的外部声明
Inner inner=new Inner();
inner.showInner(name);
}
public static void main(String[] args) {
PartialDemo partialDemo = new PartialDemo();
partialDemo.demo();
}
}
三、匿名内部类
匿名内部类中不能定义任何静态成员、方法和类,可以存在,但无法调用。
- 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。但是并没有看到extends和implements关键字,这是因为匿名内部类没有连类名都没有,使用关键字就更无从说起了,这些由jvm搞定了。
- 匿名内部类中是不能定义构造函数的。
- 匿名内部类中不能存在任何的静态成员变量和静态方法。
- 匿名内部类为局部(方法)内部类,所以局部内部类的所有限制同样对匿名内部类生效。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
1.匿名内部类是子类
public class Animals {
//方法类型Animals
public Animals eat() {
System.out.println();
return this;
}
//方法类型为void
public void sleep() {
System.out.println("动物都要睡觉");
}
}
public class AnimalsClass {
public static void main(String[] args) {
//继承匿名内部类写法
Animals a = new Animals() {
public Animals eat() {
System.out.println("匿名内部类父类方法eat类型Animals");
return this;
}
public void sleep() {
System.out.println("匿名内部类父类方法sleep类型void");
}
public void run() {//此次不报错
System.out.println("匿名内部类自己的方法");
}
};
a.eat();
a.sleep();
//a.run();//此处检查异常,报错,匿名内部类不能有自己的方法
}
}
2.匿名内部类是接口实现类
烂写法:
常用写法,即以实参的形式使用:
//定义一个接口
public interface Animals {
public abstract void eat();
}
class P implements Animals{
public void eat() {
System.out.println("吃东西");
}
}
public class AnimalsImpl {
public static void main(String[] args) {
//方法一
// P p = new P();
// run(p);
//方法二
// run(new P());
//方法三,最好,防止浪费资源
run(new Animals() {
public void eat() {
System.out.println("实参");
}
});
}
/**
* 想调用这个run方法,但还不进行接口实现
* 因为接口实现只使用一次的话,那这种实现就是浪费资源
* 所以这个时候推荐使用匿名内部类,也是匿名内部类的主要用途
* @param a
*/
private static void run(Animals a) {
a.eat();
}
}
四、静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}