类的五大成员:属性、方法、构造方法、代码块、内部类
内部类
在一个类里边再定义一个类。可以在外部其他类中创建内部类对象并调用它的方法
public class Outer {//外部类
public class inner{//内部类
}
}
内部类使用时机:
- 内部类表示的事物是外部类的一部分
- 内部类单独出来没有任何意义
特点:
1.内部类可以直接访问外部类的成员,包括私有
2.外部类要访问内部类的成员必须创建对象
package day15.demo10;
public class Car {
String carname;
int age;
String color;
class engine{
String name;
int age;
public void show(){
System.out.println(name);
System.out.println(carname);
}
}
engine engine = new engine();
public void show(){
System.out.println(carname);
System.out.println(engine.name);
}
}
内部类分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类:
写在成员位置的,属于外部类的成员
可以被权限修饰符修饰
类定义在了成员位置 (类中方法外称为成员位置,无static修饰的内部类)
使用方法:
外部类.内部类。 // 访问内部类的类型都是用 外部类.内部类
获取成员内部类对象:
法一:在外部类中编写方法,对外提供内部类对象
public class Outer {
String outername;
private class Inner{
String innername = null;
}
public Inner getinstance(){
return new Inner();
}
}
===========================================================================================
public class main {
public static void main(String[] args) {
// Outer.Inner inner = new Outer().new Inner();
// inner.innername = "hello";
// System.out.println(inner.innername);
Outer outer = new Outer();
outer.getinstance();
System.out.println(outer.getinstance());
}
}
法二:直接创建格式:外部类.内部类 对象名 = 外部类对象.内部类对象
public class main {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.innername = "hello";
System.out.println(inner.innername);
}
}
内部类访问外部类的成员变量
public class Outer {
private int a = 10;
class Inner{
private int a = 20;
public void show(){
int a = 30;
System.out.println(a);
System.out.println(this.a);
System.out.println(Outer.this.a);
}
}
}
为什么是Outer.this.a?
通过Java内存分析工具我们可以看到,内部类Inner中隐含一个Outer.this来记录外部类的地址值,当内部类访问外部类的成员变量的时候会通过内部类隐含的Outer.this来访问Outer类进而访问其成员变量。
可以看到,内部类和外部类是两个不同的类,通过Outer.this来记录内部类外部类的关系
静态内部类:
成员内部类被static修饰时就称为静态内部类
静态内部类只能访问外部类中的静态变量和静态方法,如果要想访问非静态的需要创建对象
创建静态内部类对象格式:外部类.内部类 对象名 = new 外部类.内部类();
调用非静态方法的格式:先创建对象,用对象调用
调用静态方法格式:外部类.内部类.方法名();
public class Outer {
int a = 10;
static int b = 20;
static class Inner{
public void show1(){
Outer outer = new Outer();
System.out.println(outer.a);
System.out.println(b);
System.out.println("show1");
}
public static void show2(){
System.out.println("show2");
}
}
}
==========================================================================================
public class main {
public static void main(String[] args) {
Outer.Inner o = new Outer.Inner();
o.show1();
Outer.Inner.show2();//调用静态方法
}
}
局部内部类:
1.将内部类定义在方法内就叫做局部内部类,类似于方法里边的局部变量
2.外界无法直接使用,需要在方法内部创建对象并调用
3.该类可以直接访问外部类的成员,也可以直接访问方法内的局部变量
注 : 不能用权限修饰符修饰
public class Outer {
int b = 20;
public void show(){
int a = 10;
class Inner{//局部内部类
String name;
int age;
public void method(){
System.out.println(b);
System.out.println("Inner");
}
public void method2(){
System.out.println("Inner static");
}
}
Inner inner = new Inner();
System.out.println(inner.name);
System.out.println(inner.age);
inner.method();
inner.method2();
}
}
匿名内部类:
匿名内部类本质上就是隐藏了名字的内部类,是内部类的简化写法
格式:
new 类名或者接口名() {
重写方法;
};
包含了:
-
继承或者实现关系
-
方法重写
-
创建对象
public interface swim {
void swim();
}
===========================================================================================
public class main {
public static void main(String[] args) {
new swim(){
@Override
public void swim() {
System.out.println("swim");
}
};
}
}
绿色的框表示的是没有名字的对象,new是用来创建此类。类实现了swim接口实现的重写 。
如果swim是类的话,就是继承关系,匿名内部类继承了名为swim的抽象类
main$1为编译生成的匿名内部类字节码文件,可以通过Javap进行反编译字节码文件,可以看到匿名内部类与接口之间的实现关系或者和类之间的继承关系
使用时机:
一个类在只使用一次时,在使用一个类时需要再创建一个类太麻烦了,此时使用匿名内部类的形式简化代码。当将匿名内部类调用的接口赋值给一个对象时候,此时就形成了接口的多态。
package day15.demo15;
public class main {
public static void main(String[] args) {
new swim(){
@Override
public void swim() {
System.out.println("swim");
}
}.swim();
// new Outer() {
// @Override
// public void eat() {
//
// }
// };
// dog dog = new dog();
// method(dog);传统方法
method(//匿名内部类形式 多态
new Outer() {
@Override
public void eat() {
System.out.println("狗吃屎");
}
}
);
}
public static void method(Outer a){
a.eat();
}
}
注意事项:
- 匿名内部类是隐藏了名字的类,可以写在成员位置,也可以写在局部位置
- 匿名内部类包含了继承或实现,方法重写,创建对象。 整体就是一个类的子类对象或者接口实现类的对象
- 当一个方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象,如果实现类只需要使用一次,就可以用匿名内部类简化代码。