1、内部类:
定义在另外一个类里面的类,就叫做内部类,为了区别,把外面的类称为外部类。
2、分类
根据内部类的所在的位置不同:
(1)成员内部类:外部类中方法外
(2)局部内部类:方法体内,(虽然也可以在代码块内,但是不讨论这个)
成员内部类:
(1)有static修饰的:静态成员内部类,我们通常就简称为静态内部类
(2)没有static修饰的:非静态成员内部类,我们通常就简称为成员内部类
【修饰符】 class 外部类{
【其他修饰符】 static class 静态内部类{
}
【其他修饰符】 class 非静态成员内部类{
}
}
【修饰符】 class 外部类 【extends 父类】 【implements 父接口们】{
【其他修饰符】 static class 静态内部类 【extends 父类】 【implements 父接口们】{
}
【其他修饰符】 class 非静态成员内部类 【extends 父类】 【implements 父接口们】{
}
}
说明:外部类、内部类的父类、父接口没有关系,各是各的
局部内部类:
(1)有名字的局部内部类:简称局部内部类
(2)没名字的局部内部类:简称匿名内部类
局部内部类的语法格式:
【修饰符】 class 外部类 【extends 父类】 【implements 父接口们】{
【修饰符】 返回值类型 方法名(【形参列表】){
【修饰符】 class 有名字的局部内部类 【extends 父类】 【implements 父接口们】{
...
}
}
}
匿名内部类的语法格式:
特殊
import java.util.Arrays;
import java.util.Comparator;
/*
* 一、匿名内部类
* 语法格式:
* new 父类名(【实参列表】){
* 类的成员列表
* }
* 说明:如果你子类调用的是父类的无参构造,那么()中实参列表不用写,如果子类调用的是父类的有参构造,那么就在()中传入实参列表
* 或
* new 父接口名(){
* 类的成员列表
* }
*
* 特殊:声明匿名内部类与创建它的对象是一起完成的。即匿名内部类只有唯一的对象。
*
*/
public class TestAnonymousInner {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
//1、需求1:要声明一个Object的子类,匿名子类,
//并在子类中声明一个方法public void test(){}打印“hello匿名内部类"
//下面这段代码,声明了匿名内部类,也创建了它的对象
//但是没有说这个对象干什么,编译不通过的。
/* new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
}*/
//(1)我们可以把这个对象,赋值给一个变量
//多态引用
Object obj1 = new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
};
System.out.println(obj1.getClass());//获取对象的运行时类型
System.out.println(obj1);//打印对象时,自动对象的toString()
//这是另一个Object的匿名子类的对象
/* Object obj2 = new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
};*/
// (2)我们可以用这个对象,直接调用方法
//匿名内部类的匿名对象.方法()
new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
}.test();
//java.util.Comparator接口
//我要在这里声明一个比较器类型,用于比较两个圆的半径大小
//把一个Comparator接口的匿名实现类对象,赋值给Comparator的变量
//多态引用
/* Comparator c = new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Circle c1 = (Circle) o1;
Circle c2 = (Circle) o2;
if(c1.getRadius() > c2.getRadius()){
return 1;
}else if(c1.getRadius() < c2.getRadius()){
return -1;
}
return 0;
}
};
System.out.println(c.compare(new Circle(1), new Circle(2)));*/
Circle[] all = new Circle[3];
all[0] = new Circle(3);
all[1] = new Circle(2);
all[2] = new Circle(1);
//匿名内部类的匿名对象作为实参使用
Arrays.sort(all, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Circle c1 = (Circle) o1;
Circle c2 = (Circle) o2;
if(c1.getRadius() > c2.getRadius()){
return 1;
}else if(c1.getRadius() < c2.getRadius()){
return -1;
}
return 0;
}
});
}
}
/*class RadiusComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Circle c1 = (Circle) o1;
Circle c2 = (Circle) o2;
if(c1.getRadius() > c2.getRadius()){
return 1;
}else if(c1.getRadius() < c2.getRadius()){
return -1;
}
return 0;
}
}*/
class Circle{
private double radius;
public Circle(double radius) {
super();
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public String toString() {
return "Circle [radius=" + radius + "]";
}
}
类的成员:
1、属性:成员变量
2、方法:成员方法
3、构造器
4、代码块
5、内部类:成员内部类
其中1、2是代表这类事物的特征
其中3、4是初始化类和对象用的
其中5协助完成2的功能的实现,表现
什么情况下会用到成员内部类(方法外声明的)?
当描述一个事物时,发现它的内部还有一个完整的结构需要用一个类来描述;
并且发现这内部的结构,如果独立存在是没有意义的,必须在这个外部类中才有意义。而且这个内部结构只为这个外部类服务。
例如:Body身体,发现它内部还有完整的结构,例如:心脏
发现心脏单独创建对象没有意义,只有在Body对象中才有意义,而且只为Body对象服务。
/*
* 成员内部类分为两种:
* 1、静态成员内部类,简称静态内部类
* 【修饰符】 class 外部类{
* 【其他修饰符】 static class 内部类{
* }
* }
* 【修饰符】 class 外部类 【 extends 父类】 【implements 父接口们】{
* 【其他修饰符】 static class 内部类 【 extends 父类】 【implements 父接口们】{
* }
* }
* 注意:只有成员内部类才能用static修饰,其他的外部类,局部内部类等都不可以用static修饰
*
* 2、非静态成员内部类
* 【修饰符】 class 外部类{
* 【其他修饰符】 class 内部类 {
* }
* }
* 【修饰符】 class 外部类 【 extends 父类】 【implements 父接口们】{
* 【其他修饰符】 class 内部类 【 extends 父类】 【implements 父接口们】{
* }
* }
*/
public class TestMemberInner {
}
class Outer{
//静态内部类
static class Inner{
}
//非静态内部类
class Nei{
}
}
静态内部类:
/*
* 二、静态内部类
*
* 1、特点
* (1)静态内部类中,可以出现原本类中能够定义的所有的成员
* 属性:可以有静态属性和非静态属性
* 方法:可以有静态方法和非静态方法
* 如果静态内部类是抽象类的话,还可以定义抽象方法
* 构造器:有参、无参
* 代码块:可以有静态代码块和非静态代码块
* 内部类:允许,很少再写内部类(不讨论内部类的内部类)
*
* (2)静态内部类中不能使用外部类的非静态的成员
* (3)在外部类中,使用静态内部类,和使用其他的类一样的原则
* 如果使用静态内部类的静态成员,直接“静态内部类名.”
* 如果使用静态内部类的非静态成员,直接“静态内部类对象名.”
* (4)在外部类的外面,使用静态内部类
* 如果使用静态内部类的静态成员,直接“类名.”
* 使用外部类名.静态内部类名.静态方法
* 使用import 包.外部类名.静态内部类名; 在代码中使用 “静态内部类名.”
* 如果使用静态内部类的非静态成员,“静态内部类对象名.”
*
* (5)静态内部类不会随着外部类的初始化一起初始化,而是要在使用到这个静态内部类是才会初始化
*
*
* 2、结论
* (1)同级的来说静态的不能直接使用非静态的
* (2)访问一个类的静态成员,用“类名.”即可,
* 访问一个类的非静态成员,用“对象名.”即可,
* (3)一个类需要初始化,得用到这个类
*/
public class TestStaticInner {
public static void main(String[] args) {
/*// Inner.test();//上面有导包语句,import 包.外部类名.静态内部类名;
Outer.Inner.test();//外部类名.静态内部类名.静态方法
// Inner in = new Inner();//上面有导包语句,import 包.外部类名.静态内部类名;
Outer.Inner in = new Outer.Inner();
in.method();*/
Outer out = new Outer();
out.outMethod();
}
}
class Outer{
private int i = 1;
private static int j = 2;
static{
System.out.println("外部类的静态代码块");
}
static class Inner{
static{
System.out.println("静态内部类的代码块");
}
public void method(){
System.out.println("静态内部类的非静态方法");
// System.out.println(i);//错误
System.out.println(j);
}
public static void test(){
System.out.println("静态内部类的静态方法");
}
}
public void outMethod(){
Inner in = new Inner();
in.method();//非静态方法,用对象名.访问
Inner.test();//静态方法,用类名.访问
}
}
非静态成员内部类:
//import com.atguigu.test02.Outer.Inner;
/*
* 二、静态内部类
*
* 1、特点
* (1)静态内部类中,可以出现原本类中能够定义的所有的成员
* 属性:可以有静态属性和非静态属性
* 方法:可以有静态方法和非静态方法
* 如果静态内部类是抽象类的话,还可以定义抽象方法
* 构造器:有参、无参
* 代码块:可以有静态代码块和非静态代码块
* 内部类:允许,很少再写内部类(不讨论内部类的内部类)
*
* (2)静态内部类中不能使用外部类的非静态的成员
* (3)在外部类中,使用静态内部类,和使用其他的类一样的原则
* 如果使用静态内部类的静态成员,直接“静态内部类名.”
* 如果使用静态内部类的非静态成员,直接“静态内部类对象名.”
* (4)在外部类的外面,使用静态内部类
* 如果使用静态内部类的静态成员,直接“类名.”
* 使用外部类名.静态内部类名.静态方法
* 使用import 包.外部类名.静态内部类名; 在代码中使用 “静态内部类名.”
* 如果使用静态内部类的非静态成员,“静态内部类对象名.”
*
* (5)静态内部类不会随着外部类的初始化一起初始化,而是要在使用到这个静态内部类是才会初始化
*
*
* 2、结论
* (1)同级的来说静态的不能直接使用非静态的
* (2)访问一个类的静态成员,用“类名.”即可,
* 访问一个类的非静态成员,用“对象名.”即可,
* (3)一个类需要初始化,得用到这个类
*/
public class TestStaticInner {
public static void main(String[] args) {
/*// Inner.test();//上面有导包语句,import 包.外部类名.静态内部类名;
Outer.Inner.test();//外部类名.静态内部类名.静态方法
// Inner in = new Inner();//上面有导包语句,import 包.外部类名.静态内部类名;
Outer.Inner in = new Outer.Inner();
in.method();*/
Outer out = new Outer();
out.outMethod();
}
}
class Outer{
private int i = 1;
private static int j = 2;
static{
System.out.println("外部类的静态代码块");
}
static class Inner{
static{
System.out.println("静态内部类的代码块");
}
public void method(){
System.out.println("静态内部类的非静态方法");
// System.out.println(i);//错误
System.out.println(j);
}
public static void test(){
System.out.println("静态内部类的静态方法");
}
}
public void outMethod(){
Inner in = new Inner();
in.method();//非静态方法,用对象名.访问
Inner.test();//静态方法,用类名.访问
}
}
局部内部类:
/*
* 四、局部内部类(最少使用的一种,几乎见不着)
* 1、声明的位置很特殊:在方法体内
*
* 2、特点
* (1)局部内部类的修饰符,只能有abstract或final
* (2)有作用域
* (3)如果局部内部类在静态方法中,不能使用外部类的非静态成员
* (4)在局部内部中,可以使用当前局部内部类所在方法的局部变量,
* 但是要求,这个局部变量必须是final的常量。
*
* 在Java8时,如果某个局部变量被局部内部类使用了,会自动添加final变为常量,一旦变为常量,它的值就不能修改了。
*
* 为什么它要这么要求?加final
* 避免局部内部类对象被返回到外部类的外面使用时,访问不到这个局部变量,所以要把这个局部变量变为final的常量。
*
*/
public class TestLocalInner {
public static void main(String[] args) {
Outer out = new Outer();
Father in = out.test();//在外部类的外面虽然不能使用局部内部类,但是可以得到它的对象
System.out.println(in.getClass());
in.method();//在这里仍然可以访问到这个a,那么这个a就不能存在栈中,得挪到方法区,变为常量
}
}
abstract class Father{
public abstract void method();
}
class Outer{
private int i = 1;//成员变量,实例变量,非静态成员变量
private static int j = 2;//成员变量,类变量,静态变量
public Father test(){
// Inner in = new Inner();
final int a = 10;//局部变量==>局部的常量
//局部内部类
class Inner extends Father{
public void method(){
System.out.println(i);
System.out.println(j);
System.out.println(a);
}
}
Inner in = new Inner();
in.method();
return in;
}
public void method(){
// Inner in = new Inner();
}
public static void fun(){
//局部内部类
class Inner{
public void method(){
// System.out.println(i);//是因为fun方法是静态的
System.out.println(j);
}
}
}
}