java内部类
1 内部类概述
1 概念: 在一个类的内部在定义一个完整的类
2 特点:
- 编译之后可以生成独立的字节码文件。
- 内部类可以直接访问外部类的私有成员,而不破坏封装
2 成员内部类
1.成员内部类的定义
- 在类的内部定义,与实例变量, 实例方法同级别的类;
- 外部类中的一个实例部分,创建内部类对象时,必须依赖外部类对象
2.成员内部类的创建
-
内部类的创建,首先要先new一个外部类对象,在通过外部类对象再new一个内部类对象,格式如下:
方法一: //1.实例化一个外部类 Outer outer=new Outer(); //2.再通过外部类实例化内部类 Outer.Inner inner=outer.new Inner();*/ 方法二:一部到位 Outer.Inner inner=new Outer().new Inner();
-
内部类也可是多个的,如下面代码中的InnerTwo类。
3.内部类中属性的调用
- 可以通过内部类来调用外部类的私有属性。
- 当外部类和内部类的属性名相同时,我们默认调用的时内部类的属性,要想调用外部的属性,可以通过 外部类名.this.外部类属性名,当属性名不同时也可以使用这中方式,这是一个好习惯。
- 在内部类中无法创建static 变量,如果创建,会报错,但是可以创建 static final 常量。
- 内部类也会由构造器(构造方法),当我们实例化一个外部类对象时,会执行外部类的构造器。当我们一部到位实例化一个内部类的对象时,首先会执行外部类构造器,再次会执行内部类的构造器。例如案例2
案例1:
package com.ouc.dem01;
public class Outer {//这是一个外部类
//实例变量
private String name="张三";
private int age=20;
//内部类
class Inner{//这是一个内部类
private String address="北京";
private String phone="10";
private String name="李四";
/*
private static String country="中国";//内部类中无法定义静态变量
*/
//但是可以定义静态常量
private static final String country="中国";
public void show(){
//打印外部类的属性,当内部类属性和外部类属性的名字相同时可是由 外部类名.this 来访问
System.out.println(Outer.this.name);//访问外部类的名字
System.out.println(Outer.this.age);//访问外部类的年龄
//打印内部类的属性。
System.out.println(address);
System.out.println(phone);
}
}
//这是第二个内部类
class InnerTwo{
private String name="王五";
public void run(){
System.out.println("run");
}
}
}
//测试类,main()方法
package com.ouc.dem01;
public class TestOuter {
public static void main(String[] args) {
/* //1.创建外部类对象
Outer outer=new Outer();
//2.创建内部类对象
Outer.Inner inner=outer.new Inner();*/
//一部到位
Outer.Inner inner=new Outer().new Inner();
Outer.InnerTwo innerTwo=new Outer().new InnerTwo();
}
}
案例2:
package com.ouc.dem02;
public class Outer {
//这是外部类的构造器
public Outer(){
System.out.println("我是Outer的构造方法");
}
//这是内部类的构造器
class Inner{
Inner(){
System.out.println("我是Inner的构造方法");
}
}
}
package com.ouc.dem02;
public class TestOuter {
public static void main(String[] args) {
// Outer outer=new Outer(); //只创建外部类对象时,只会执行外部类构造器
//当创建内部类对象时,会先执行外部类构造器,然后执行内部类的构造器
Outer.Inner inner=new Outer().new Inner();
}
}
3 静态内部类
1. 静态内部类的定义:
- static修饰的类,static 关键字表示类的属性和方法,static 修饰的属性和方法 是和类一个放入内存的,在成员内部类的基础之上,给类添加了一个static关键字,这样就变成了一个静态内部类。
2.静态内部类创建:
- 静态内部类不依赖外部类对象 ,可直接创建或者通过类名访问,可声明静态成员。
- 使用static关键字修饰后,内部类和外部类的级别相同,不再是和外部的实例变量同一个级别。
- 静态内部类可以创建静态属性,而成员内部类不行。
3. 静态内部类如何访问外部类的是属性
- 由于静态内部类和外部类的级别一致,需要访问静态内部类的属性是,我们需要先实例化一个外部类对象,再通对象.属性名来访问
4. 什么要有静态类
既然静态类和外部类的级别相同,那不是和我们平时写的类一样了吗?为啥要再内部定义静态内部类呢。原因就是静态内部类可以为外部类提供一些功能。
5. 关于静态内部类的构造器
- 当我们实例化一个外部类时,会执行外部类的构造器,当我们实例化静态内部类时,只会执行静态内部类的构造器,不会执行外部类的构造器,例如案例2;
- 这里和成员内部类不一样,成员内部类实例化时,首先会执行外部类的构造器,再执行内部类的构造器,而静态内部类只会执行自己的构造器。
注意: 只有静态内部类才可以用static来修饰,普通的类不能用static来修饰。
案例1
package com.ouc.dem04;
public class Outer {
private String name="海文宇";
private int age=18;
static class Inner{
private String address="深圳";
private String phone="111";
//静态内部类可以是设置静态变量
private static String country="中国";
public void show(){
//如何调用外部类的属性
//1.创建外部类对象
Outer outer=new Outer();
//2.通过对象.方法名来访问.
System.out.println(outer.name);
System.out.println(outer.age);
//调用静态类的内部属性
System.out.println(address);
System.out.println(phone);
}
}
}
package com.ouc.dem04;
public class TestOuter {
public static void main(String[] args) {
Outer.Inner inner=new Outer.Inner();
inner.show();
}
}
案例2
package com.ouc.dem04;
public class Outer {
//这是外部类的构造器
public Outer(){
System.out.println("我是Outer的构造方法");
}
static class Inner{
Inner(){
System.out.println("我是Inner的构造方法");
}
}
}
package com.ouc.dem04;
public class TestInner {
public static void main(String[] args) {
//实例化一个Outer对象
Outer outer=new Outer();
//实例化一个Inner对象
Outer.Inner inner=new Outer.Inner();
}
}
4 局部内部类
1. 局部类的定义
- 定义再外部类的方法中,作用范围和创建对象的范围仅限于当前方法。
2. 局部内部类的创建
- 局部内部类在类的外部类的方法中创建
- 具备外部类创建时不能用修饰符修饰
3. 关于局部内部类的调用
- 局部内部类可以直接访问外部类的属性
- 但是局部内部类不能访问外部类的静态属性和静态方法
- 局部内部类在调用外部类的属性时,可以直接调用,但是建议写上Outer.this.属性,增加代码的可读性。
- 在局部内部类中,要想调用内部类的方法,首先要在在创建局部内部类的方法中实例化,在通过实例化对象类调用内部类的方法。
- 在局部内部类中调用方法中的属性(即调用局部变量),在jdk1.7以前时要求属性为常量,所以要加final,但是jdk1.8以后就不用了,系统默认为常量,所以调用后的属性值就不可修改了。
- 同样的局部类中不能存在static变量,但是可以存在static final 常量。
4.关于局部内部类的构造器
- 局部内部类的构造器的执行,首先要实例化外部类对象,然后通过外部类对象调用方法,但是由前提时该方法中应该堆内部类进行实例化,如果部进醒实例化,那这样也不花执行内部类的构造器。
案例1
package com.ouc.dem05;
public class Outer{
private String name="海文宇";
private int age=18;
public void show(){
//定义一个局部变量
String address="深圳";
System.out.println("run");
//局部内部类,定义再方法中
/*
局部内部类之前不能加任何的访问修饰符
*/
class Inner{
//局部内部类的属性
private String phone="13712431236";
private String email="32559773q@qq.com";
public void show2(){
//访问外部类的属性
System.out.println(Outer.this.name);
System.out.println(Outer.this.age);
//访问内部类的属性
System.out.println(this.email);
System.out.println(this.phone);
/*访问方法中的属性,address
在jdk1.7中:要求必须时常量;在jdk1.8中,不用,应为会默认的给他加final
所以,address被默认为常量,就不可修改*/
System.out.println(address);
}
}
Inner inner=new Inner();
inner.show2();
}
}
package com.ouc.dem05;
public class TestIOuter {
public static void main(String[] args) {
Outer outer=new Outer();
outer.show();
}
}
案例2
package com.ouc.dem06;
public class Outer {
public Outer(){
System.out.println("我是Outer的构造器");
}
public void show(){
class Inner{
Inner(){
System.out.println("我是Inner构造器");
}
}
Inner inner=new Inner();
}
}
package com.ouc.dem06;
public class TestOuter {
public static void main(String[] args) {
Outer outer=new Outer();
outer.show();
}
}
5 匿名内部类
1. 匿名内部类的定义
- 匿名内部类就是没有名字的局部内部类,他的一切特性和局部内部类相同
- 必须继承一个父类和接口
- 匿名内部类实际上就是定义类,实现类,创建对象的语法合并,只能创建一个该类的对象
- 优点:减少代码量;缺点:可读性差;
案例1
package com.ouc.dem07;
//这是一个接口
public interface Usb {
//定义了一个服务方法
void server();
}
package com.ouc.dem07;
public class Mouse implements Usb {
@Override
public void server() {
System.out.println("连接电脑成功,鼠标开始工作了");
}
}
package com.ouc.dem07;
public class TestUsb {
public static void main(String[] args) {
/* Usb usb=new Mouse();
usb.server();*/
/* //在main方法中 定义一个局部内部类
class Fan implements Usb{
@Override
public void server() {
System.out.println("连接电脑成功,风扇开始工作了");
}
}
//使用局部类创建对象
Usb usb=new Fan();
usb.server();*/
//使用匿名内部类优化(相当创建了一个局部类)
Usb usb=new Usb() {
@Override
public void server() {
System.out.println("连接电脑成功,风扇开始工作了");
}
};
usb.server();
}
}
总结:
所谓内部内就是在一个类的内部定义一个完整的类,下面综合上面做做区分:
1.位置
- 成员内部类是定义在一个类里面,等级和成员变量的等级相同
- 静态内部类也是定义在类里面,但是用static修饰的类
- 局部内部类定义在方法里,和方法内的属性等级相同
- 匿名内部类也是定义在方法里,但是没有名字。
2.内部类的创建
- 成员内部类的实例化要先实例化一个外部类,在通过外部类来new一个内部类。
- 静态内部类的实例化和外部类没有关系,可以直接正常实例化。
- 局部内部类无法通过外部类来实例化内部类对象,也无法在方法体外实例化这个内部类,只能在方法体里面实例化内部类。
- 匿名内部和局部内部类一样。
3.关于内部类的构造器
- 成员内部类实例化后,先执行了外部类的构造器,再执行了内部类的构造器。
- 静态内部类实例化后只会执行自己的构造器,和外部类无关。
- 局部内部类实例化只会执行自己的构造器。