面向对象初级
封装encapsulation
封装就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作
现实生活中的封装:如电视机。当用户按下电视机的音量增减按钮时,音量增减的内部电路的实现细节用户是不需要知道的。这时,按钮相当于被授权的操作,内部电路的实现细节就相当于抽象出的数据和对数据的操作。
封装的理解和好处
封装的实现步骤
封装快速入门
代码实现
class Person{
public String name;//名字公开
private int age;
private double salary;
public String getName() {
return name;
}
public void setName(String name) {
if (name.length() > 1 && name.length() < 7) {
this.name = name;
}
else {
System.out.println("名字长度不合理");
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 1 && age < 121) {
this.age = age;
}
else{
System.out.println("年龄设置不合理,给默认年龄");
this.age = 18;
}
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
构造器与setXxx结合,在使用构造器创建对象进行初始化的同时仍可以进行验证
public Person(String name, int age, double salary) {
setAge(age);//等价于this.setAge(age)
setName(name);
setSalary(salary);
}
继承extend
继承的示意图
继承基本介绍和基本语法
继承细节
1.子类继承了父类所有的属性和方法,但是私有属性和方法不能在子类直接访问,要通过公共的方法去访问
比如
class base {
}
2.子类必须调用父类的构造器,完成父类的初始化。
public class Base{
public Base() {
System.out.println("Base()...");
}
}
public class Sub extends Base {
public Sub() {
//super();//表示调用父类无参构造器
System.out.println("Sub()...");
}
}
Sub sub = new Sub();
//会输出Base()...
// Sub()...
public class Base{
// public Base() {
// System.out.println("Base()...");
// }
public Base(String name) {
System.out.println("Base(String name)...");
}
}
public class Sub extends Base {
public Sub() {
super(String name);
System.out.println("Sub()...");
}
}
Sub sub = new Sub();
//会输出Base(String name)...
// Sub()...
4.如果希望指定去调用父类的某个构造器,则得显式地调用一下:super(参数列表)
5.super在使用时,需要放在构造器第一行
6.super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
继承的本质分析
继承的内存布局
继承的查找逻辑
super
基本介绍及基本语法
使用细节
super和this的比较
方法重写
多态polymorphism
多态的基本介绍和多态的具体体现
对象的多态
向上转型
向下转型
向下转型的目的是调用子类的特殊方法和属性。
animal是向上转型出来的。Animal animal = new Cat();
animal是指向Cat类型的引用
在对animal进行向下转型时,只能强转为Cat类型。
多态的注意事项和细节讨论
属性没有重写之说,属性的值看编译类型
instanceOf 比较操作符,用于判断对象的类型是否为XX类型或XX类型的子类型
动态绑定机制DynamicBinding(重要)
java的动态绑定机制
- 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
- 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
案例分析
为什么base.Sum()为30?
当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
base的运行类型是子类Sub,getI()是一个方法,与base的运行类型Sub绑定,所以调用了子类Sub的getI(),为20,那么return的就是20+10=30了
为什么base.Sum1()为20?
当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
return的还是编译类型Base中的属性i=10,那么return的就是20
public class dynamicBinding {
public static void main(String[] args) {
Base base = new Sub();
System.out.println(base.Sum());//30
System.out.println(base.Sum1());//20
}
}
class Base {
private int i = 10;
public int Sum() {
return getI() + 10;
}
public int Sum1() {
return i + 10;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
class Sub extends Base {
private int i = 20;
@Override
public int getI() {
return i;
}
@Override
public void setI(int i) {
this.i = i;
}
}
多态数组
父类Person与两个子类Student和Teacher
public class Person {
private String name;
private int age;
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;
}
public String say() {
return "name = " + name + ", age = " + age;
}
}
public class Student extends Person{
private double score;
public Student(String name, int age, double score) {
super(name, age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String say() {
return super.say() + ", score = " + score;
}
public void Study() {
System.out.println(getName() + " is studying");
}
}
public class Teacher extends Person{
private int salary;
@Override
public String say() {
return super.say() + ", salary = " + salary;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public Teacher(String name, int age, int salary) {
super(name, age);
this.salary = salary;
}
public void Teach() {
System.out.println(getName() + " is teaching
}
}
public class main {
public static void main(String[] args) {
Person[] persons = new Person[5];//多态数组
persons[0] = new Person("Mike",20);
persons[1] = new Student("Tom",18,95);
persons[2] = new Student("Jack",19,61);
persons[3] = new Teacher("Lucy",30,15000);
persons[4] = new Teacher("Elizabeth",40,20000);
for (Person person : persons) {//增强for
// System.out.println(person.say());
if (person instanceof Teacher){//如果person是Teacher的实例或Teacher子类的实例
((Teacher) person).Teach();//向下转型,调用Teach()方法
}
if (person instanceof Student){
((Student) person).Study();
}
}
}
}
多态参数
上代码
public class Employee {
private String name;
private int salaryPerMonth;
public Employee() {
}
public int getAnnual() {
return 12 * salaryPerMonth;
}
public Employee(String name, int salaryPerMonth) {
this.name = name;
this.salaryPerMonth = salaryPerMonth;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalaryPerMonth() {
return salaryPerMonth;
}
public void setSalaryPerMonth(int salaryPerMonth) {
this.salaryPerMonth = salaryPerMonth;
}
}
public class Manager extends Employee{
private int bonus;
public Manager(String name,int salaryPerMonth,int bonus) {
super(name, salaryPerMonth);
this.bonus = bonus;
}
public int getBonus() {
return bonus;
}
public void setBonus(int bonus) {
this.bonus = bonus;
}
public void manage() {
System.out.println(this.getName() + " is managing.");
}
@Override
public int getAnnual() {
return super.getAnnual() + getBonus();
}
}
public class Worker extends Employee{
public void work() {
System.out.println(this.getName() + " is working");
}
public Worker(String name, int salaryPerMonth) {
super(name, salaryPerMonth);
}
@Override
public int getAnnual() {
return super.getAnnual();
}
}
Test类
public class Test {
public static void main(String[] args) {
Employee manager = new Manager("Jack",50000,200000);
Employee worker = new Worker("Mike",3000);
Test test = new Test();
test.showEmpAnnual(manager);//800000
test.showEmpAnnual(worker);//36000
test.testWork(manager);//Jack is managing.
test.testWork(worker);//Mike is working.
}
public void showEmpAnnual(Employee employee) {
System.out.println(employee.getAnnual());//动态绑定机制
}
public void testWork(Employee employee) {
if(employee instanceof Worker) {
((Worker) employee).work();//向下转型
}
else if(employee instanceof Manager) {
((Manager) employee).manage();
}
else {
System.out.println("不做任何处理...");
}
}
}
Object类
equals
==和equals的对比
==
equals方法
equals:是Object类中的方法,默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如Integer,String
//object类的equals
public boolean equals(Object obj) {
return (this == obj);//判断引用的地址是否相等
}
//Integer类的equals
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();//判断内容是否相等
}
return false;
}
Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
System.out.println(integer1 == integer2);//false
System.out.println(integer1.equals(integer2));//true
重写equals方法
public class Equals02 {
public static void main(String[] args) {
Person person1 = new Person("Jack",18,'男');
Person person2 = new Person("Jack",18,'男');
System.out.println(person1.equals(person2));//没重写equals之前,调用Object中的equals,返回false;重写equals之后,返回true
}
}
class Person{
private String name;
private int age;
private char gender;
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof Person){
Person p = (Person) o;
return p.age == this.age && p.gender == this.gender && p.name == this.name;
}
return false;
}
}
hashCode
hashCode()会在集合的底层源码中用到,是一个整数,主要根据地址号得到。
public class HashCode_ {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
A a3 = a1;
System.out.println("a1.hashCode() = " + a1.hashCode());
System.out.println("a2.hashCode() = " + a2.hashCode());
System.out.println("a3.hashCode() = " + a3.hashCode());
}
}
class A{
}
//a1.hashCode() = 1784662007
//a2.hashCode() = 1789550256
//a3.hashCode() = 1784662007
第(2)点一定成立
第(3)点可能不成立,两个不同对象可能会发生碰撞,概率极小。
toString
object中的toString
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
//getClass.getName() 类的全类名(包名+类名)
//Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串
示例
没有重写toString
public class toString_ {
public static void main(String[] args) {
Worker jack = new Worker("Jack", 1000, 31);
System.out.println(jack.toString());
}
}
class Worker{
private String name;
private int salary;
private int age;
public Worker(String name, int salary, int age) {
this.name = name;
this.salary = salary;
this.age = age;
}
}
//polymorphism.Object_.Worker@6a5fc7f7
重写toString之后
public class toString_ {
public static void main(String[] args) {
Worker jack = new Worker("Jack", 1000, 31);
System.out.println(jack.toString());
}
}
class Worker{
private String name;
private int salary;
private int age;
public Worker(String name, int salary, int age) {
this.name = name;
this.salary = salary;
this.age = age;
}
@Override
public String toString() {
return "Worker{" +
"name='" + name + '\'' +
", salary=" + salary +
", age=" + age +
'}';
}
}
//Worker{name='Jack', salary=1000, age=31}
finalize
System.gc()可以主动触发垃圾回收机制,调用finalize方法
断点调试debug
debug如何进入源码
Settings ==> Build,Execution,Deployment ==> Debugger ==> Stepping
取消勾选java.*
和javax.*
F7 step into:单步执行,遇到子函数就进入并且继续单步执行(简而言之,进入子函数);
F8 step over:在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步。有一点,经过我们简单的调试,在不存在子函数的情况下是和step into效果一样的(简而言之,越过子函数,但子函数会执行)。
Shift + F8 step out:当单步执行到子函数内时,用step out就可以执行完子函数余下部分,并返回到上一层函数。
F9 resume program 在分析复杂问题时,非常有用
面向对象高级
static
类变量(静态变量)
快速入门
在某个类中定义一个类变量,关键字 static。
例如public static int count = 0;
(推荐)
或者static public int count = 0;
该变量最大的特点就是会被该类的所有对象实例共享
public class example {
public static void main(String[] args) {
Child child1 = new Child("张三");
child1.Join();
child1.count++;
Child child2 = new Child("李四");
child2.Join();
child2.count++;
Child child3 = new Child("王五");
child3.Join();
child3.count++;
System.out.println("共有 " + Child.count + " 个小孩加入了游戏...");
System.out.println(child1.count);//3
System.out.println(child2.count);//3
System.out.println(child3.count);//3
}
}
class Child {
private String name;
public static int count = 0;
public Child(String name) {
this.name = name;
}
public void Join() {
System.out.println(name + " 加入了游戏...");
}
}
类变量是随着类的加载而创建的,所以即使没有创建对象实例也可以访问
public class example {
public static void main(String[] args) {
System.out.println(Child.count);//0
}
}
class Child {
public static int count = 0;
}
类变量使用注意事项和细节讨论
类方法
快速入门
统计学生交的总学费
public class method_ {
public static void main(String[] args) {
Student jack = new Student("Jack");
Student mike = new Student("Mike");
jack.payFee(100);
mike.payFee(200);
//输出当前收到的总学费
Student.showFee();//300
}
}
class Student {
private String name;
private static double fee = 0;
public Student(String name) {
this.name = name;
}
public static void payFee(double fee) {
Student.fee += fee;
}
public static void showFee() {
System.out.println("总学费有:" + Student.fee);
}
}
什么时候使用静态方法?
如果我们希望不创建实例,也可以调用某个方法时(当成工具类),把方法做成静态方法非常合适。如Arrays类、Math类、Collections集合类
在实际开发中,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用这些方法,比如冒泡排序,打印数组等。
类方法使用注意事项和细节讨论
小练习
main方法
main方法语法
特别提示
public class Main01 {
private static String name = "Lucy";
private int n1 = 100;
public static void hello() {//只能调用静态成员和静态方法
System.out.println("Main01中的静态hello方法被调用 : " + "hello " + name);
}
public void hi() {//既可以调用静态成员和静态方法,也可以调用非静态成员和非静态方法
System.out.println("Main01中的非静态hi方法被调用 : " + "hi " + name);
}
public static void main(String[] args) {
//main方法可以直接调用本类内的静态成员
System.out.println("name = " + name);
hello();
//main方法中,在调用本类的非静态成员时,要先对类实例化
Main01 main01 = new Main01();
main01.hi();
System.out.println(main01.n1);
}
}
代码块
代码块的好处和案例演示
案例演示
public class example {
public static void main(String[] args) {
new Movie("Avatar: The Way of Water",51.8,"James Cameron");
}
}
class Movie {
private String name;
private double price;
private String director;
{
System.out.println("观众入场...");
System.out.println("电影屏幕打开...");
System.out.println("电影正式开始...");
}
public Movie(String name) {
/*System.out.println("观众入场...");
System.out.println("电影屏幕打开...");
System.out.println("电影正式开始...");*/
System.out.println("Movie(String name)被调用");
this.name = name;
}
public Movie(String name, double price) {
/*System.out.println("观众入场...");
System.out.println("电影屏幕打开...");
System.out.println("电影正式开始...");*/
System.out.println("Movie(String name, double price)被调用");
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
/*System.out.println("观众入场...");
System.out.println("电影屏幕打开...");
System.out.println("电影正式开始...");*/
System.out.println("Movie(String name, double price, String director)被调用");
this.name = name;
this.price = price;
this.director = director;
}
}
//输出结果:
//观众入场...
//电影屏幕打开...
//电影正式开始...
//Movie(String name, double price, String director)被调用
(5) 先调用代码块中的语句,再调用构造器中的语句
使用细节
static代码块在类加载时被调用,且只能被调用一次
普通代码块在new对象实例时会被调用,new一次,就会调用一次。如果只是使用类的静态成员,普通代码块并不会被执行。
代码块的调用顺序
public class detail02 {
public static void main(String[] args) {
new BBB();
}
}
class AAA {
{
System.out.println("AAA的普通代码块...");
}
public AAA() {
System.out.println("AAA() 构造器被调用...");
}
}
class BBB extends AAA{
{
System.out.println("BBB的普通代码块...");
}
public BBB() {
System.out.println("BBB() 构造器被调用...");
}
}
单例设计模式
什么是设计模式
什么是单例模式
wiki上的解释
In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to a singular instance. One of the well-known “Gang of Four” design patterns, which describe how to solve recurring problems in object-oriented software,[1] the pattern is useful when exactly one object is needed to coordinate actions across a system.
More specifically, the singleton pattern allows objects to:[2]
- Ensure they only have one instance
- Provide easy access to that instance
- Control their instantiation (for example, hiding the constructors of a class)
The term comes from the mathematical concept of a singleton.
饿汉式(即使没有需要使用实例对象,也会在类加载的时候创建实例对象)
public class singleTon01 {
public static void main(String[] args) {
GirlFriend instance = GirlFriend.getInstance();
System.out.println(instance);
}
}
class GirlFriend {
private String name;
//为什么是static?静态成员在类加载的时候加载,并且只会加载一次,符合单例设计模式中只生成一个对象实例的要求
private static GirlFriend gf = new GirlFriend("小红");
//步骤[单例模式-饿汉式]
//1.将构造器私有化
//2.在类的内部直接创建(static)
//3.提供一个公共的static方法,返回 gf 对象
private GirlFriend(String name) {
this.name = name;
}
public static GirlFriend getInstance() {
return gf;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
'}';
}
}
懒汉式(在需要使用时才创建实例对象)
public class singleTon02 {
public static void main(String[] args) {
Cat cat1 = Cat.getInstance();
Cat cat2 = Cat.getInstance();
System.out.println(cat1);
System.out.println(cat2);
System.out.println(cat1 == cat2);
}
}
class Cat {
private String name;
private static Cat cat = null;
private Cat(String name) {
System.out.println("Cat()构造器被调用...");
this.name = name;
}
public static Cat getInstance() {
if (cat == null){
cat = new Cat("小可爱");
}
return cat;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
//Cat()构造器被调用...
//Cat{name='小可爱'}
//Cat{name='小可爱'}
//true
饿汉式与懒汉式对比
final关键字
基本介绍
final细节
细节一
final修饰类的某个属性时,必须赋值
1.定义时:如 public final double TAX_RATE=0.08;
2.在构造器中
3.在代码块中
如果final修饰的属性是静态的,则初始化的位置只能是1.定义时和2.在静态代码块中
细节二
关于第7点
抽象类
当使用abstract关键字修饰类的方法时,这个类也必须被abstract关键字修饰
抽象类细节
(8)抽象方法不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的
被private修饰的方法,子类无法访问
被final修饰的方法,子类无法重写/覆盖
被static修饰的:重写的作用是为了父类和子类的相同签名的方法,具有不同的行为,从而实现了多态。但是静态方法是被类直接调用的,和对象无关,不存在父子类对象之间的相同方法不同行为,所以也没有多态。
抽象模板模式(Template method pattern)
wiki:
在面向对象编程中,模板方法是Gamma等人[1]确定的行为设计模式之一。 在设计模式一书中。 模板方法是超类(通常是抽象超类)中的一种方法,它根据许多高级步骤定义操作的骨架。 这些步骤本身由与模板方法相同的类中的其他辅助方法实现。
辅助方法可以是抽象方法,在这种情况下子类需要提供具体实现,也可以是钩子方法,在超类中具有空主体。 子类可以(但不是必须)通过覆盖挂钩方法来自定义操作。 模板方法的目的是定义操作的整体结构,同时允许子类改进或重新定义某些步骤。 [2] 动态绑定机制
示例
abstract public class Template {
abstract public void job();
public void calculateTime() {
long start = System.currentTimeMillis();
job();
long end = System.currentTimeMillis();
System.out.println("执行的时间为 " + (end - start));
}
}
public class AA extends Template{
@Override
public void job() {
int num = 0;
for (int i = 0;i < 8000000;i++) {
num += i;
}
System.out.print("AA ");
}
@Override
public void calculateTime() {
super.calculateTime();
}
}
public class BB extends Template{
@Override
public void job() {
int num = 0;
for (int i = 0;i < 800000;i++) {
num *= i;
}
System.out.print("BB ");
}
@Override
public void calculateTime() {
super.calculateTime();
}
}
public class TestTemplate {
public static void main(String[] args) {
AA aa = new AA();
BB bb = new BB();
aa.calculateTime();
bb.calculateTime();
}
}
//AA 执行的时间为 4
//BB 执行的时间为 2
接口(Interface)
快速入门
注意“统一的规定”
public interface UsbInterface {
public void start();
public void end();
}
public class Phone implements UsbInterface{
@Override
public void start() {
System.out.println("Phone start to work...");
}
@Override
public void end() {
System.out.println("Phone end working...");
}
}
public class Cemera implements UsbInterface{
@Override
public void start() {
System.out.println("Cemera start to work...");
}
@Override
public void end() {
System.out.println("Cemera end working... ");
}
}
public class Computer {
public void ComputerWork(UsbInterface usbInterface){
usbInterface.start();
usbInterface.end();
}
}
public class UsbInterfaceApp {
public static void main(String[] args) {
Computer computer = new Computer();
Phone phone = new Phone();
Cemera cemera = new Cemera();
computer.ComputerWork(phone);
System.out.println("===========");
computer.ComputerWork(cemera);
}
}
//Phone start to work...
//Phone end working...
//===========
//Cemera start to work...
//Cemera end working...
基本介绍
Java编程语言中的接口是一种抽象类型,用于描述类必须实现的行为。它们类似于协议。接口使用interface关键字声明,并且只能包含方法签名和常量声明(变量声明被声明为静态和final)。在Java 8以下的所有版本中,接口的所有方法都不包含实现(方法体)。从Java 8开始,默认方法和静态方法可以在接口定义中实现然后,在Java 9中添加了私有和私有静态方法。目前,一个Java接口最多可以有六种不同的类型。
接口不能被实例化,而是被实现。实现接口的类必须实现接口中描述的所有非默认方法,或者是一个抽象类。Java中的对象引用可以指定为接口类型;在每种情况下,它们要么必须为空,要么必须绑定到实现接口的对象。
使用接口的一个好处是它们可以模拟多重继承。Java中的所有类都必须有一个基类,唯一的例外是Java .lang. object (Java类型系统的根类);不允许类的多重继承。然而,一个接口可以继承多个接口,一个类可以实现多个接口。
使用场景
顶层设计,利用接口的继承和多态特性来规范类的实现。
案例
需求:
没有使用接口
方法不规范,不统一。
使用接口后
类的方法变得规范,统一,符合工业场景了。
细节
内部类
基本介绍以及基本语法
内部类很重要,底层源码中有大量内部类
内部类的分类
局部内部类(Local Class)
public class localInnerClass {
private int n1 = 10;
private static String name = "张三";
public void say() {
int n3 = 30;
// 局部内部类的作用域只能在定义它的代码块或方法中,
// 因此也不能用public修饰,但是可以使用final修饰
class LocalInner01 {//相当于一个局部变量
int n2 = 40;
int n1 = 60000;//当内部类成员和外部类成员重名时,遵从就近原则。如果要访问外部类的成员,需要使用 外部类名.this.成员
public void show() {
//局部内部类可以直接访问外部类的所有成员,包括私有的
System.out.println("n1 = " + n1);
System.out.println("外部类的n1 = " + localInnerClass.this.n1);
}
}
LocalInner01 localInner01 = new LocalInner01();
localInner01.show();
}
public static void main(String[] args) {
localInnerClass localInnerClass = new localInnerClass();
localInnerClass.say();
}
}
//n1 = 60000
//外部类的n1 = 10
匿名内部类(Anonymous)
虽然我们在代码中看不到名字,但系统给它分配了名字
案例演示
public class AnonymousInner01 {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.method();
}
}
class Outer01{
private int n1 = 10;
public void method() {
/* CryInterface tiger = new Tiger();
tiger.cry();*/
CryInterface tiger = new CryInterface() {
@Override
public void cry() {
System.out.println("A tiger is crying...");
}
};
tiger.cry();
//1.如果接口的实现类(或者父类的子类)只需要使用唯一一次,那么这种情况下我们就可以省略掉对该类的定义,而改为使用匿名内部类。
//2.匿名内部类可以用来简化开发。
//3.tiger的编译类型是? CryInterface
//4.tiger的运行类型是? Outer01$1
//5.底层
/*class Outer01$1 implements CryInterface {
@Override
public void cry() {
System.out.println("A tiger is crying...");
}
}*/
//在创建Outer01$1之后,马上创建了Outer01$1的实例,并且把地址返回给了tiger
//6.匿名内部类在使用一次之后就不能再次使用
System.out.println("tiger的匿名内部类的名称是 " + tiger.getClass());
}
}
interface CryInterface {
void cry();
}
/*
class Tiger implements CryInterface{
@Override
public void cry() {
System.out.println("A tiger is crying...");
}
}*/
//A tiger is crying...
//tiger的匿名内部类的名称是 class InnerClass.Outer01$1
匿名内部类的使用场景
当作实参直接传递,简洁高效
public class AnonymousInner01 {
public static void main(String[] args) {
show(new CryInterface() {
@Override
public void cry() {
System.out.println("A dog is crying...");
}
});
//传统方法
show(new Dog());
}
public static void show(CryInterface cryInterface) {
cryInterface.cry();
}
}
interface CryInterface {
void cry();
}
//类->实现接口CryInterface 在编程中属于硬编码
//当我们修改类中的方法时,所有的Dog实例都会被修改
class Dog implements CryInterface {
@Override
public void cry() {
System.out.println("A dog is crying...");
}
}
//A dog is crying...
//A dog is crying...
练习
public class AnonymousInner02 {
public static void main(String[] args) {
Clock clock = new Clock();
clock.AlarmClock(new Bell() {
@Override
public void ring() {
System.out.println("上课啦,叮叮叮...");
}
});
clock.AlarmClock(new Bell() {
@Override
public void ring() {
System.out.println("下课啦,呱呱呱...");
}
});
}
}
interface Bell {
void ring();
}
class Clock {
public void AlarmClock(Bell bell) {
bell.ring();
}
}
成员内部类(Member Class)
public class MemberClass {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.method();
}
}
class Outer02 {
private int n1 = 10;
public String name = "张三";
class Inner02 {//成员内部类,地位相当于外部类的一个成员,所以也可以用private protected public 来修饰
public void say() {
//成员内部类的方法可以直接访问外部类的成员
System.out.println("n1 = " + n1 + " name = " + name);
}
}
public void method() {
Inner02 inner02 = new Inner02();
inner02.say();
}
}
//n1 = 10 name = 张三
public class MemberClass {
public static void main(String[] args) {
//使用成员内部类的方式
//1.
Outer02.Inner02 inner02 = outer02.new Inner02();
inner02.say();
//2.
Outer02.Inner02 instance = outer02.getInstance();
instance.say();
}
}
class Outer02 {
private int n1 = 10;
public String name = "张三";
class Inner02 {//成员内部类,地位相当于外部类的一个成员,所以也可以用private protected public 来修饰
public void say() {
//成员内部类的方法可以直接访问外部类的成员
System.out.println("n1 = " + n1 + " name = " + name);
}
}
public Inner02 getInstance() {
return new Inner02();
}
}
静态内部类static class