面向对象进阶
一、static-静态属性
static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量
-
被static修饰的成员变量,叫做静态变量
- 特点:
- 被该类所有对象共享
- 跟对象无关,随着类的加载而加载,优先于对象存在
- 调用方式:
- 类名调用(推荐)
- 对象名调用
- 特点:
-
被static修饰的成员方法,叫做静态方法
- 特点:
- 多用在测试类和工具类中
- Javabean类中很少会用
- 调用方式:
- 类名调用(推荐)
- 对象名调用
- 特点:
类
- JavaBean类
- 用来描述一类事物的类。比如,Student,Teacher,Dog,Cat等
- 测试类
- 用来检查其他类是否书写正确,带有main方法的类,是程序的入口
- 工具类
- 不是用来描述一类事物的,而是帮我们做一些事情的类。
1.1、工具类
- 类名见名知意
- 私有化构造方法
- 方法定义为静态
用工具类构造方法,相当于构造函数,如果定义好了工具类,那么直接再次想要复用方法时,可以直接复制类中的代码。
1.2、static的注意事项
- 静态方法只能访问静态变量和静态方法
- 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法
- 静态方法中是没有this关键字
总结:
静态方法中,只能访问静态。
非静态方法可以访问所有。
静态方法中没有this关键字
1.3、重新认识main方法
public class Helloworld {
public static void main(String[] args) {
system.out.println( "Helloworld");
}
}
public
: 被JVM调用,访问权限足够大static
:被JVM调用,不用创建对象,直接类名访问因为main方法是静态的,所以测试类中其他方法也需要是静态的。void
:被JVM调用,不需要给JVM返回值main
:一个通用的名称,虽然不是关键字,但是被JVM识别String[] args
:以前用于接收键盘录入数据的,现在没用
二、继承
2.1、继承的概念
封装:对象代表什么,就得封装对应的数据,并提供数据对应的行为
继承:
- Java中提供一个关键字
extends
,用这个关键字,我们可以让一个类和另一个类建立起继承关系。
public class Student/*子类*/ extends Person/*父类*/ {
}
- Student称为子类(派生类),Person称为父类(基类或者超类)
使用继承的好处:
- 可以把多个子类中重复的代码抽取到父类中了,提高代码的复用性。
- 子类可以在父类的基础上,增加其他的功能,使子类更强大。
什么时候用继承?
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码
2.2、继承的特点和继承体系的设计
Java只支持单继承,不支持多继承,但支持多层继承。
- 单继承:一个子类只能继承一个父类
- 不支持多继承:子类不能同时继承多个父类
- 多层继承:子类A继承父类B,父类B可以继承父类C
每一个类都直接或者间接的继承于Object(祖宗类)
总结
- Java只能单继承,不能多继承、但是可以多层继承。
- Java中所有的类都直接或者间接继承于Object类。
- 子类只能访问父类中非私有的成员
2.3、子类到底能继承父类中的那些内容
-
构造方法
- 构造方法不能被子类继承下来
构造方法的方法名需要与类名相同,如果继承下来的话两者就不相同了所以无法继承
- 构造方法不能被子类继承下来
-
成员变量
- 无论是否私有都能被成员变量继承,不过私有的不能直接使用
无private修饰类型:
- 成员方法
2.4、继承中成员变量和成员方法的访问特点
成员变量的访问特点
- 就近原则:谁离得近访问谁
- 先在局部位置找,本类成员位置找,父类成员位置找,逐级往上。
重名:
package entends.aFUzientends;
public class Text{
public static void main(String[] args){
zi z = new zi();
z.ziShow();
}
}
class Fu {
String name = "fu";
}
class zi extends Fu{
String name = "zi";
public void ziShow(){
String name = "zishow";
System.out.println(name);//zishow
System.out.println(this.name);//zi
System.out.println(super.name);//fu
}
}
super指向下会调用父类里面的成员变量
this指向下会调用子类里面的成员变量,如果子类没有就会向父类寻找
没有指向就会采用就近原则来调用变量
成员方法的访问特点
- 直接调用满足就近原则:谁离我近,我就用谁
- super调用,直接访问父类
方法的重写
当父类的方法不能满足子类现在的需求时,需要进行方法重写
书写格式
在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
@Override重写注解
-
@Override
是放在重写后的方法上,校验子类重写时语法是否正确。 -
加上注解后如果有红色波浪线,表示语法错误。
-
建议重写方法都加
@Override
注解,代码安全,优雅!
方法重写注意事项和要求- 重写方法的名称、形参列表必须与父类中的一致。
- 子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解 :空着不写< protected < public)
- 子类重写父类方法时,返回值类型子类必须小于等于父类
- 建议:重写的方法尽量和父类保持一致。
- 只有添加到虚方法表中的方法才能被重写
2.5、利用方法的重写设计继承结构
package entends.chongxieAnimal;
public class Text {
public static void main(String[] args) {
hasky dog1 = new hasky();
shapi dog2 = new shapi();
chineseDog dog3 = new chineseDog();
dog1.Eat();
dog2.Eat();
dog3.Eat();
dog1.play();
dog2.drink();
dog3.lookhome();
}
}
package entends.chongxieAnimal;
public class Dog {
public void Eat(){
System.out.println("吃狗粮");
}
public void drink(){
System.out.println("喝水");
}
public void lookhome(){
System.out.println("看家");
}
}
package entends.chongxieAnimal;
public class chineseDog extends Dog{
@Override
public void Eat(){
System.out.println("吃剩饭");
}
}
package entends.chongxieAnimal;
public class hasky extends Dog {
public void play(){
System.out.println("拆家");
}
}
package entends.chongxieAnimal;
public class shapi extends Dog {
@Override
public void Eat(){
super.Eat()
System.out.println("吃骨头);
}
}
2.6、继承中的构造方法
- 父类中的构造方法不会被子类继承
- 子类中所有的构造方法默认先访问父类中的无参构造,再执行自己。
为什么?
- 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
- 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
怎么调用父类构造方法的?
- 子类构造方法的第一行语句默认都是: super(),不写也存在,且必须在第一行。
- 如果想调用父类有参构造,必须手动写**super()**进行调用。
public class Person (){
String name;
int age;
pnblic Person(){
System.out.println("父类的无参构造")
}
pnblic Person(String name,int age){
this.name = name;
this.age = age;
}
}
public class Student (){
public Student(){
super();
System.out.println("子类的无参构造")
}
public Student (String name,int age){
super(name,age);
}
}
public class Text(){
public static void main(String[] args){
Student s = new Student(zhangsan,23);
}
}
2.7、this super关键字
- this:理解为一个变量,表示当前方法调用者的地址值;
- super:代表父类存储空间。
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量 访问本类成员变量 | this.成员方法 访问本类成员方法 | this.(…) 访问本类构造方法 |
super | super.成员变量 访问父类成员变量 | super.成员方法 访问父类成员方法 | super.(…) 访问父类构造方法 |
2.8、练习-带有继承结构的标准JavaBean类
package entends.extendsjavabean;
public class text {
Manger a = new Manger(001,"xiaoli",8000,3000);
cooker b = new cooker(002,"xiaowang",8000);
}
package entends.extendsjavabean;
public class Emplyee {
private int num;
private String name;
private int money;
public void work(){
System.out.println("员工在工作");
}
public void eat(){
System.out.println("吃米饭");
}
public Emplyee() {
}
public Emplyee(int num, String name, int money) {
this.num = num;
this.name = name;
this.money = money;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String toString() {
return "Emplyee{num = " + num + ", name = " + name + ", money = " + money + "}";
}
}
package entends.extendsjavabean;
public class Manger extends Emplyee{
private int boen;
public Manger() {
}
public Manger(int num,String name,int money,int boen) {
super(num,name,money);
this.boen = boen;
}
public int getBoen() {
return boen;
}
public void setBoen(int boen) {
this.boen = boen;
}
public String toString() {
return "Manger{boen = " + boen + "}";
}
@Override
public void work() {
System.out.println("管理别人");
}
}
package entends.extendsjavabean;
public class cooker extends Emplyee{
@Override
public void work() {
System.out.println("炒菜");
}
public cooker(){
}
public cooker(int num,String name,int money){
super(num,name,money);
}
}
三、多态
3.1、认识多态
什么是多态?
同类型的对象,表现出的不同形态。
多态的表现形式
父类类型 对象名称=子类对象
;
多态的前提
- 有继承关系
- 有父类引用指向子类对象
Fu f = new Zi()
; - 方法重写
多态的好处
使用父类型作为参数,可以接受所有子类对象,体现多态的扩展性与便利
3.2、多态中调用成员的特点
- 变量调用:编译看左边,运行也看左边。
- 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。
- 运行也看左边:java运行代码的时候,实际获取的就是左边父类中成员变量的值
- 方法调用:编译看左边,运行看右边。
- 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有编译失败。
- 运行看右边: java运行代码的时候,实际上运行的是子类中的方法。
3.3、多态的优势和弊端
优势:
- 在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
- 定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
弊端:
- 不能调用子类的特有功能
//假设有三个类,其中animal类是Dog类和Cat类的父类
//进行类的转换
animal a = new Dog;
if(a instanceof Dog){
Dog b = (Dog)a;
b.lookhome();
}else if (a instanceof Cat c){
Cat c = (Cat)a;
c.catmouse();
}else{
System.out.println("没有这个类型,无法转换")
}
//JDK14之后的新特性
if(a instanceof Dog b){
b.lookhome();
}else if (a instanceof Cat c){
c.catmouse();
}else{
System.out.println("没有这个类型,无法转换")
}
3.4、多态的综合练习
package entends.Polymorphism02;
public class Text {
public static void main(String[] args) {
Dog b = new Dog(2,"黑色");
Cat c = new Cat(2,"白色");
Person p = new Person("老王",40);
p.keepPet(b,"骨头");
p.keepPet(c,"小鱼干");
}
}
package entends.Polymorphism02;
public class animal {
private int age;
private String color;
public animal() {
}
public animal(int age, String color) {
this.age = age;
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat(String somthing){
System.out.println("正在吃东西");
}
}
package entends.Polymorphism02;
public class Dog extends animal {
public Dog(int age,String color){
super(age,color);
}
@Override
public void eat(String somthing){
System.out.println(getAge()+"岁的"+getColor()+"的狗正在抱着"+somthing+"吃");
}
public void lookHome(){
System.out.println("狗正在看家");
}
}
package entends.Polymorphism02;
public class Cat extends animal{
public Cat(int age,String color){
super(age,color);
}
@Override
public void eat(String somthing){
System.out.println(getAge()+"岁的"+getColor()+"的猫正在抱着"+somthing+"吃");
}
public void catchMouse(){
System.out.println("猫正在抓老鼠");
}
}
package entends.Polymorphism02;
public class Person {
private String name;
private int age;
public Person() {
}
public void keepPet(animal a,String something){
if(a instanceof Dog b){
System.out.println(getAge()+"岁的"+getName()+"正在用"+something+"喂养狗");
b.eat(something);
} else if (a instanceof Cat c) {
System.out.println(getAge()+"岁的"+getName()+"正在用"+something+"喂养猫");
c.eat(something);
}
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.5、包和final
包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。
- 包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。
包名+类名 被称为:全类名或者全限定名
使用其他类的规则
- 使用同一个包中的类时,不需要导包。
- 使用java.lang包中的类时,不需要导包。
- 其他情况都需要导包
- 如果同时使用两个包中的同名类,需要用全类名。
final
- 用final修饰一个方法:表明该方法是最终方法,不能被重写
- 用final修饰一个类:表明该类是最终类,不能被继承
- 用final修饰一个变量:叫做常量,只能被赋值一次
常量
实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。常量的命名规范:
- 单个单词:全部大写
- 多个单词:全部大写,单词之间用下划线隔开
细节:
- final修饰的变量是基本类型:那么变量存储的数据值不能发生改变
- final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,对象内部的可以改变。
- 常量记录的数据是不能改变的
3.6、权限修饰符
- 权限修饰符:是用来控制一个成员能够被访问的范围的。
- 可以修饰成员变量,方法,构造方法,内部类。
实际开发中,一般只用private和public
- 成员变量私有
- 方法公开
特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有。
3.7、代码块
- 局部代码块
- 写在括号里面的代码块
- 构造代码块
- 作用:可以把多个构造方法中重复的代码抽取出来
- 执行时机:我们在创建本类对象的时候会先执行构造代码块在执行代码块
- 写在成员位置中,把带参构造以及无参构造的函数里面相同的代码抽取出来,放在代码块(括号),就是构造代码块
- 静态代码块
- 格式
static{}
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
- 使用场景:在类加载的时候,做一些数据初始化的时候使用
- 格式
四、抽象类与接口
4.1、抽象类和抽象方法
- 抽象方法:将共性的行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样,所以,在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。
- 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
抽象类和抽象方法的定义格式
- 抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表)
; - 抽象类的定义格式:
public abstract class 类名{}
;
抽象类和抽象方法到的注意事项
- 抽象类不能实例化
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 可以有构造方法
- 抽象类的子类
- 要么重写抽象类中的所有抽象方法
- 要么是抽象类
package abstract_.A0dome1;
public abstract class animal {
private String name;
private int age;
public animal() {
}
public animal(String name, int age) {
this.name = name;
this.age = age;
}
public void drink(){
};
public abstract void eat();
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "animal{name = " + name + ", age = " + age + "}";
}
}
package abstract_.A0dome1;
public class Dog extends animal {
public Dog(String name,int age) {
super(name,age);
}
@Override
public void eat() {
System.out.println("吃骨头");
}
}
package abstract_.A0dome1;
public class frog extends animal{
public frog(String name,int age) {
super(name,age);
}
@Override
public void eat() {
System.out.println("吃虫子");
}
}
package abstract_.A0dome1;
public class sheep extends animal{
public sheep(String name,int age) {
super(name,age);
}
@Override
public void eat() {
System.out.println("吃草");
}
}
package abstract_.A0dome1;
public class Text {
public static void main(String[] args) {
Dog d = new Dog("quiqui",2);
frog f = new frog("xiao",2);
sheep s = new sheep("meiyangyang",3);
d.eat();
f.eat();
s.eat();
}
}
4.2、接口
接口的定义和使用
- 接口用关键字interface来定义
public interface接口名{}
; - 接口不能实例化
- 接口和类之间是实现关系,通过implements关键字表示
public class类名implements接口名l - 接口的子类(实现类)
要么重写接口中的所有抽象方法
要么是抽象类
注意1:接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements接口名1,接口名2{}
;
注意2:实现类还可以在继承一个类的同时实现多个接口。
public class 类名 extends 父类 implements接口名1,接口名2{}
;
package interface_.aDome1;
public abstract class animal {
private String name;
private int age;
public animal() {
}
public animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void eat();
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "animal{name = " + name + ", age = " + age + "}";
}
}
package interface_.aDome1;
public class dog extends animal implements swim{
public dog(){
};
public dog(String name ,int age){
super();
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void swim() {
System.out.println("狗刨");
}
}
package interface_.aDome1;
public class forg extends animal implements swim{
public forg(){
};
public forg(String name ,int age){
super(name,age);
}
@Override
public void eat() {
System.out.println("青蛙吃虫子");
}
@Override
public void swim() {
System.out.println("蛙泳");
}
}
package interface_.aDome1;
public class rabbit extends animal{
public rabbit(){
};
public rabbit(String name ,int age){
super();
}
@Override
public void eat() {
System.out.println("兔子吃胡萝卜");
}
}
package interface_.aDome1;
public interface swim {
void eat();
public abstract void swim();
}
package interface_.aDome1;
public class Text {
public static void main(String[] args) {
dog g = new dog("quiqui",2);
forg f =new forg("qiongwa",2);
rabbit r = new rabbit("tuzxi",3);
g.eat();
g.swim();
f.eat();
f.swim();
r.eat();
}
}
4.3、接口的细节
接口中成员的特点
- 成员变量
- 只能是常量
- 默认修饰符:
public
static final
- 构造方法
- 没有
- 成员方法
- 只能是抽象方法
- 默认修饰符:public abstract
- JDK7以前:接口中只能定义抽象方法。
- JDK8的新特性:接口中可以定义有方法体的方法。
- JDK9的新特性:接口中可以定义私有方法。
接口和类之间的关系
- 类跟类的关系
- 继承关系,只能单继承,不能多继承,但是可以多层继承
- 类和接口的关系
- 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 接口和接口的关系
- 继承关系,可以单继承,也可以多继承
4.4、练习-编写带有接口和抽象类的标准JavaBean类
package interface_.aDome2;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Person{name = " + name + ", age = " + age + "}";
}
}
package interface_.aDome2;
public abstract class Player extends Person {
public Player(){
};
public Player(String name,int age){
super(name,age);
};
public abstract void study();
}
package interface_.aDome2;
public abstract class trainer extends Person {
public trainer(){
};
public trainer(String name,int age){
super(name,age);
};
public abstract void teaching();
}
package interface_.aDome2;
public interface english {
public abstract void sayenglish();
}
package interface_.aDome2;
public class basketballplay extends Player{
public basketballplay(){
};
public basketballplay(String name,int age){
super(name,age);
};
@Override
public void study() {
System.out.println("学篮球");
}
}
package interface_.aDome2;
public class basketballtariner extends trainer {
public basketballtariner(){
};
public basketballtariner(String name,int age){
super(name,age);
};
@Override
public void teaching() {
System.out.println("学篮球");
}
}
package interface_.aDome2;
public class pingpangplayer extends Player implements english{
public pingpangplayer(){
};
public pingpangplayer(String name,int age){
super(name,age);
};
@Override
public void study() {
System.out.println("学乒乓球");
}
@Override
public void sayenglish() {
System.out.println("说英语");
}
}
package interface_.aDome2;
public class pingpangtrainer extends Player implements english{
public pingpangtrainer(){
};
public pingpangtrainer(String name, int age) {
super(name,age);
}
@Override
public void study() {
System.out.println("教乒乓球");
}
@Override
public void sayenglish() {
System.out.println("说英语");
}
}
4.5、多学三招
JDK8开始接口中新增的方法
JDK7以前:接口中只能定义抽象方法。
JDK8的新特性:接口中可以定义有方法体的方法。(默认、静态)
JDK9的新特性:接口中可以定义私有方法。
JDK8新特性
-
允许在接口中定义默认方法,需要使用关键字default修饰
- 作用:解决接口升级的问题
-
接口中默认方法的定义格式:
格式:public default 返回值类型 方法名(参数列表){}
; -
接口中默认方法的注意事项:
- 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉
default
关键字 public
可以省略,default
不能省略- 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
- 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉
-
允许在接口中定义定义静态方法,需要用static修饰
-
接口中静态方法的定义格式:
- 格式:
public static 返回值类型 方法名 (参数列表) {}
; - 范例:
public static void show(){ }
;
- 格式:
-
接口中静态方法的注意事项:
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public可以省略,static不能省略
JDK9新增的方法
接口的私有方法,此方法只为Inter接口提供服务,不需要外类访问
接口中私有方法的定义格式:
普通的私有方法(为普通的方法服务):
- 格式1:
private 返回值类型 方法名 (参数列表) {}
; - 范例1:
private void show(){}
;
静态的私有方法(为静态的方法服务):
- 格式2:
private static 返回值类型 方法名 (参数列表){}
; - 范例2:
private static void method(){}
;
接口的应用
- 接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
- 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。
适配器设计模式
- 当一个接口中抽象方法过多,但是我只要使用其中一部分的
时候,就可以适配器设计模式 - 书写步骤:
- 编写中间类XXXAdapter实现对应的接口
- 对接口中的抽象方法进行空实现
- 让真正的实现类继承中间类,并重写需要用的方法
- 为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰
五、内部类
5.1、初始内部类
类的五大成员:
属性,方法,构造方法,代码块,内部类
- 在一个类的里面,再定义一个类
当B类表示的事物是A类的一部分,且B单独存在没有意义,此时就可以使用到内部类
5.2、内部类的分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类的代码如何书写
- 写在成员位置的,属于外部类的成员
- 成员内部类可以被一些修饰符所修饰,比如:private,默认,protected, public, static等
- 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量
public class Car{
//外部类
String carName;
int carAge;
int carColor;
class Engine(//成员内部类
String engineName;
int engineAge;
)
}
- 用private修饰的成员内部类只能在本类里面进行实例化
获取成员内部类对象
- 方法一:
在外部类中编写方法,对外提供内部类的对象。 - 方式二:
直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
;
成员内部类如何获取外部类的成员变量
外部类变量名和内部类变量成员变量重名时,在内部类如何访问
System.out.println(Outer.this.变量名)
package innerclass.aDome1;
public class Outer {
String name;
private int a = 10;
public 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);
}
}
}
package innerclass.aDome1;
public class text {
public static void main(String[] args) {
Outer.Inner o = new Outer().new Inner();
o.show();
}
}
5.3、静态内部类
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。
创建静态内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名()
;
- 例:
Outer.inner oi = new Outer.inner()
调用非静态方法的格式:先创建对象,用对象调用
调用静态方法的格式:外部类名.内部类名.方法名()
;
5.4、局部内部类
- 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
- 外界是无法直接使用,需要在方法内部创建对象并使用。
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
5.5、匿名内部类
匿名内部类本质上就是隐藏了名字的内部类
//格式:
new 类名或者接口名(){
重写方法;
};
- 继承\实现
- 方法重写
- 创建对象
例:
new Inter(){
public void show(){
}
};
-
什么是匿名内部类?
隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。 -
格式的细节
包含了继承或实现,方法重写,创建对象。
整体就是一个类的子类对象或者接口的实现类对象 -
使用场景
当方法的参数是接口或者类时,
以接口为例,可以传递这个接口的实现类对象,
如果实现类只要使用一次,就可以用匿名内部类简化代码。