第二节 java面向对象

1.概述

类:对现实生活中一类具有共同属性和行为的事物的抽象。(对事物的一种描述,如手机类,它可以是小米、华为等不同品牌的手机)

对象:看得到摸得着的真实存在的实体。(真实存在的事物,如手机的价格)

 

2.类的定义

2.1 定义步骤:①成员属性;②成员方法(注意:不要加static关键字)。

public class Phone {
    /**定义步骤:
     * 1.成员属性
     * 2.成员方法
     */
    String brand;//手机品牌
    Double price;//价格
    
    public void call(){
        System.out.println("打电话");
    }
    public void sendMsg(){
        System.out.println("发短信");
    }
}

 

3.对象的使用

3.1 创建对象(注意要在main方法中)

格式:类名 对象名 = new 类名(); 例如:Phone phone1 = new Phone();

3.2 使用对象

3.2.1 使用成员变量

格式:对象名.变量; 例如:Phone1.brand = “xiaomi”;

3.2.2 使用成员方法

格式:对象名.方法名 例如:phone1.call();

public class Phone {
    String brand;
    Double price;

    public void call(String brand){
        System.out.println("使用"+brand+"打电话");
    }
	//注意:最好不要在定义的类里面直接用主方法,建议新建一个类再用主方法(下面只是为了方便演示)。
    public static void main(String[] args) {
        //创建对象
        Phone phone1 = new Phone();//创建对象
        phone1.brand = "小米";//
        phone1.price = 1999.0;
        System.out.println(phone1.brand);
        System.out.println(phone1.price);
        phone1.call("小米");//调用方法
    }
}

 

4.对象的内存

简单了解一下对象的内存地址。

 

5.成员/局部变量

5.1 成员变量

概念:类的方法之外的变量。

5.2 局部变量

概念:类的方法之中的变量。注意:方法中传递的参数(形参)也是局部变量。如:

public void work(int j){ //这个“j”是局部变量。
	//一些内容
}

5.3 二者的区别

区别 成员变量 局部变量
位置 类的方法外 类的方法里
内存 堆内存 栈内存
生命周期 随对象而存在或消失 随方法调用而存在或消失
初始值

6.权限修饰符private

6.1 private可以修饰“成员变量”和“成员方法”。

6.2 被修饰的成员只能在本类中访问,因而可保护成员不被其它类使用。

6.3 如果要设置成员变量的值可用“ public void set变量名()”方法。如果要获取成员变量的值可用“public get变量名()”方法。

 

7.关键字this

7.1 方法的形参与成员变量参数名相同时,不带this的参数,指形参(局部变量);方法的形参与成员变量参数名不同时,不带this的参数,指成员变量

7.1.1 如下,this.name指成员变量,而name为方法的形参(局部变量)

String name = "john"
public void setName(String name){
	this.name = name;
}

 

7.1.2 如下,第3行的name均为局部变量

String name = "john"
public void setName(String name){
	name = name;
    //第3行相当于省略了一行 String name; 
}

7.2 什么时候用this?解决局部变量隐藏成员变量。this:代表所在的类对象的引用,方法被哪个对象调用,this就代表哪个对象。

7.3 this关键字的使用细节

①this关键字可用来访问本类的属性、方法、构造方法(构造函数)。 ②this用于区分当前类的成员变量和局部变量。 ③无参构造方法中调用“有参构造方法”使用this赋值时,this必须放在构造方法的第一条语句。

 

8.构造方法

8.1 概念:构造方法(又叫“构造函数”)是一种特殊的方法,作用是创建对象,完成对象数据的初始化(简单说就是给成员变量赋值)。分为无参构造方法和有参构造方法2种。

8.2 格式:

public class Student{
	修饰符 类名(参数){
		内容;
	}
}

8.3 注意:

①类的名称必须与方法的名称相同。

②如果类中没有定义任何构造方法,系统会自动生成一个“无参构造方法”。如果类中定义了一个有参的构造方法,则需要单独定义一个“无参构造方法”。

//有参构造方法:
public Student(String name){
	this.name = name;
}


//无参构造方法:
public Student(){
	System.out.println("Student已经初始化。");
}
//在另一个类中,调用Student()无参构造方法,来创建对象
public class StudentDemo1 {
    public static void main(String[] args) {
        Student s1 = new Student();
    }
}

8.4 构造方法的例题

//第一个类中:
public class Student {
    /**
     * 1.成员变量
     */
    private String name;
    private int age;
    /**
     * 2.构造函数(构造方法)
     */
    // 无参构造方法
    public Student(){
        System.out.println("使用无参构造方法赋值:");
    }
    // 有参构造方法
    public Student(String name,int age){
        System.out.println("使用有参构造方法赋值:");
        this.name = name;
        this.age = age;
    }
    /**
     * 3.成员方法,setXxx()/getXxx()/toString()
     */
    public void setName(String name){
        this.name = name;
    }
    public void setAge(int age){
        this.age = age;
    }
    public String getName(){
        return name;
    }
    public int getAge(){
        return age;
    }
    //返回该类中,所有成员变量的值
    public String toString(){
        return name+"--" + age;
    }
}

//第二个类中:
public class StudentDemo1 {
    public static void main(String[] args) {
        //1.使用无参构造方法,用set方法赋值
        Student s1 = new Student();
        s1.setName("mayikt");
        s1.setAge(21);
        System.out.println(s1.toString());

        //2.使用有参构造方法,赋值
        Student s2 = new Student("meite",23);
        System.out.println(s2.toString());
    }
}

8.5 idea自动生成模板类

public class Student {
    private String name;
    private int age;
    //生成无参构造函数:在idea软件中,右键,选择“Generate...”,再选择“constructor”。
    public Student() {
    }
    //生成有参构造函数(需先定义参数,再生成)
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //生成get和set方法:在idea软件中,右键,选择“Generate...”,再选择“Getter and Setter”。

    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;
    }
    //生成toString方法:在idea软件中,右键,选择“Generate...”,再选择“toString()”。

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 

9.封装

9.1 概念:

把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行隐藏。(面向对象有三个基本特征,即封装、继承、多态)

9.2 规则:

①将类的某些信息隐藏在类的内部,不允许外部的程序直接访问。

②通过该类提供的方法来实现对隐藏信息的操作和访问。

9.3实现:

①修改属性为私有(private);

②创建getter/setter方法;

③在getter/setter方法中加入属性控制语句(对属性的合法性进行判断)。

 

10.继承

10.1 概念:使子类具有父类的属性和方法,还可以在子类中重新定义、追加属性和方法。

10.2格式:

public class 子类名 extends 父类名{ }

10.3 注意:

①父类也称为基类、超类,父类主要存放子类中相同的成员属性和方法。

②子类也称为派生类,子类主要存放不同成员属性和方法。

③java中一个子类只能继承一个父类(一个父类可以被多个子类继承);此外,可以使用多层继承。

10.4 优缺点

①优点:提高代码的复用性及维护性。

②缺点:继承让类与类之间产生了关系,增加了耦合性,当父类变化时,子类也不得不变化,削弱了子类的独立性。因此,不能滥用继承。

10.5 变量的访问特点(就近原则)

先查找当前方法的局部变量,(没有)再查找当前子类的成员变量,(没有)再查找其父类的成员变量。

10.6 作业题

猫和狗的共同特性是属于动物。思想如下:

①定义动物类Animal,成员变量:姓名、年龄,构造方法:无参、有参,成员方法:get/set方法。

②定义猫类Cat,继承动物类,构造方法:无参,有参,成员方法:抓老鼠catchMouse。

③定义狗类Dog,继承动物类,构造方法:无参、有参,成员方法:看门lookDoor。

④定义测试类AnimalDemo,写代码测试。

//1.创建一个AnimalParent类
public class AnimalParent {
    /**
     * 10.6 作业题
     *
     * 猫和狗的共同特性是属于动物。思想如下:
     *
     * ①定义动物类Animal,成员变量:姓名、年龄,构造方法:无参、有参,成员方法:get/set方法。
     *
     * ②定义猫类Cat,继承动物类,构造方法:无参,有参,成员方法:抓老鼠catchMouse。
     *
     * ③定义狗类Dog,继承动物类,构造方法:无参、有参,成员方法:看门lookDoor。
     *
     * ④定义测试类AnimalDemo,写代码测试。
     */
    private String name;
    private int age;
    public AnimalParent() {

    }
    public AnimalParent(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;
    }
}

//2.创建一个Cat类
public class Cat extends AnimalParent{
    public Cat() {
    }
    public Cat(String name, int age){
        super(name, age);
    }

    public void catchMouse(){
        System.out.println("抓老鼠");
    }
}

//3.创建一个Dog类
public class Dog extends AnimalParent{
    public Dog(String name, int age) {
        super(name, age);
    }
    public Dog() {
    }
    public void lookDoor(){
        System.out.println("看大门");
    }
}

//4.创建一个AnimalDemo类(测试有参构造方法赋值)
public class AnimalDemo {
    public static void main(String[] args) {
        /**
         * 使用有参构造方法给成员属性赋值
         */
        //创建猫对象
        Cat cat1 = new Cat("小猫A",3);
        Cat cat2 = new Cat("小猫B",4);
        System.out.println(cat1.getName()+","+cat1.getAge());
        System.out.println(cat2.getName()+","+cat2.getAge());
        System.out.println("----------");
        //创建狗对象
        Dog dog1 = new Dog("小黄狗",5);
        Dog dog2 = new Dog("小白狗",5);
        System.out.println(dog1.getName()+","+dog1.getAge());
        System.out.println(dog2.getName()+","+dog2.getAge());

    }
}

//5.创建一个AnimalDemo2类(测试无参构造方法set赋值)
public class AnimalDemo2 {
    /**
     * 使用set方法给成员属性赋值
     */
    public static void main(String[] args) {
        //猫对象
        Cat cat1 = new Cat();
        cat1.setName("小猫A");
        cat1.setAge(3);
        Cat cat2 = new Cat();
        cat2.setName("小猫B");
        cat2.setAge(4);
        System.out.println(cat1.getName()+","+cat1.getAge());
        System.out.println(cat2.getName()+","+cat2.getAge());
        System.out.println("--------");
        //狗对象
        Dog dog1 = new Dog();
        dog1.setName("小黄狗");
        dog1.setAge(5);
        Dog dog2 = new Dog();
        dog2.setName("小白狗");
        dog2.setAge(5);
        System.out.println(dog1.getName()+","+dog1.getAge());
        System.out.println(dog2.getName()+","+dog2.getAge());

    }
}

 

11.关键字super

11.1 作用:可以访问到父类的成员属性、方法、构造函数。

11.2 概念:super代表父类存储空间的标识(可理解为父类对象的引用)

11.3 使用

关键字 访问成员变量 访问构造方法 访问成员方法
super super.成员变量 super(…) super.成员方法
this this.成员变量 this(…) this.成员方法

11.4 构造方法的访问特点

①子类的构造方法默认访问父类的无参构造方法;

②子类会继承父类的数据,还会使用父类的数据,所以子类初始化前需对父类初始化;

③每个子类构造方法的第一句默认为super();

④如果父类没有无参构造方法,只有有参构造方法咋办?a.通过super关键字调用父类的有参构造方法;b.在父类中单独定义一个无参构造方法。

 

12.方法重写

12.1 概念

子类中出现了和父类一样的方法,当子类需要父类的功能,而功能主体中,子类有自己独特的内容,就需要重写父类中的方法,即延续父类的功能,又定义子类的特有功能。

12.2 注意

①子类的方法名称(参数)必须与父类保持一致。

②“@Override”是一个注解,可以帮我们检查子类的方法是否可以重写父类的方法。

③父类的私有方法,无法被子类继承。

④子类方法的访问权限不能比父类低(public > private),只能比父类高(或者叫开放)。

 

13.权限修饰符

一共有4种,可以放在 方法/属性/类 前面。

修饰符 同类 同包 不同包的子类 不同包的非子类
private(私有) × × ×
protected(受保护) √(不同包的子类继承父类时) ×
public(公开)
default(少用) × ×

 

14.包(package)

14.1 概念:就是文件夹,方便对类进行管理。

14.2 注意:直接在src目录下创建的类,没有包名。

14.3 导包:

①格式:import 类的完整路径地址(用“.”连接)。

②“*”表示导入某包下的所有类。如com.meite.*

③如果在同一个包下,默认不需要写import,但不在一个包下时,那创建对象时,就需要进行指定,如com.mykt.m1.Student s1 = new com.mykt.m1.Student();

 

15.状态修饰符

15.1 final(最终态)

final关键字可用于修饰类、成员属性、成员方法。final修饰的类无法被继承。final修饰的成员方法无法被重写。final修饰的成员属性(变量)无法被修改。

final修饰的基本数据类型的值不能被修改;final修饰的引用数据类型的引用类型地址不能修改,但地址里面的成员属性值可以修改。

15.2 static(静态)

static关键字修饰的成员方法为静态方法,修饰的成员变量为静态变量。被static修饰者,将被类的所有对象共享访问。

静态成员方法只能访问静态成员方法或静态成员属性。非静态成员方法既可以访问非静态成员方法或非静态成员属性,也可以访问静态成员方法或静态成员属性。

被static修饰的成员方法或属性,可以直接通过“类名.方法名”访问,如“Student.a1();”。

什么是常量?指定义好之后,其值不能被修改的变量,须用final来修饰,变量名要全部大写。如:public final int COODE_200 = 200;

 

16.main方法

main方法是java虚拟机在调用,因为调用时main方法和虚拟机不在同一个类,所以该方法的访问权限必须是public。java虚拟机执行main方法时,不用创建对象,所以该方法必须是static。main方法接受String类型的数组参数,该数组中保存执行java命令时传递给所执行类的参数。

main方法可以直接访问本类的静态成员,如果要访问本类的非静态成员,需要先创建对象,再调用。

 

17.多态

17.1 基本概念

多态是面向对象的三大特征之一,稍微有点抽象。

多态的3个前提条件:①有继承/实现(接口)关系,②有方法重写,③有父类引用指向子类对象。例子如下:

//第一个类AnimalParent
public class AnimalParent {
    //动物类(父类)-- 人类、猫类、狗类(子类)
    //定义一个吃方法
    public void eat(){
        System.out.println("父类(动物类)的吃方法");
    }
}

//第二个类Dog
public class Dog extends AnimalParent{
    //重写父类的eat方法
    @Override
    public void eat() {
        System.out.println("这是子类(狗类)的吃方法");
    }
}

//第三个类Test
public class Test {
    public static void main(String[] args) {
        //父类引用 指向 子类对象
        AnimalParent ap = new Dog();
        ap.eat();
    }
}

 

17.2 多态的访问特点

成员变量:编译看左边,执行看左边(等号的左边与右边);成员方法:编译看左边,执行看右边(传入的是什么,执行的就是什么)。为什么会有区别呢?因为成员方法有重写,而成员变量没有。编译阶段:指在写代码的时候,在运行之前。

17.3 多态机制的优缺点

优点:可扩展性强。代码更加简洁,新增子类时,不需要单独创建一个方法来操作,如下所示:

//类一:
public class AnimalOperate {
    //不使用多态:分为定义 调用猫和狗的吃方法
    public void userCatEat(Cat cat){
        cat.eat();
    }
    public void userDogEat(Dog dog){
        dog.eat();
    }
    //使用多态:可简化上面的代码为下面二行
    直接调用父类的吃方法,可根据传入的参数选取对应的吃方法
    public void userAnimal(AnimalParent animalParent){
        animalParent.eat();
    }
}

//类二:
public class AnimalDemo {
    public static void main(String[] args) {
        //创建 动物操作类对象
        AnimalOperate animalOperate = new AnimalOperate();
        
        //调用猫类中的eat方法
        animalOperate.userCatEat(new Cat());
        //调用狗类中的eat方法
        animalOperate.userDogEat(new Dog());
        
        System.out.println("----分隔线----");
        
        //实际是调用狗类中的eat方法
        animalOperate.userAnimal(new Dog());
        //实际是调用猫类中的eat方法
        animalOperate.userAnimal(new Cat());
    }
}

缺点:不能使用子类的特有功能。

17.4 多态的转型

向上转型:从子到父,父类引用指向子类对象。子类new出来的对象给父类接收。

向下转型(强转):从父到子,父类引用转为子类对象。可能发生类型转换异常。

 

18.抽象类

18.1 概念

在Java中,一个没有方法体的方法被定义为抽象方法,而类中如果有抽象方法,该类就定义为抽象类。抽象类和抽象方法用abstract关键字修饰。例如:抽象类:abstract class 类名{ },抽象方法:public abstract eat( );

18.2 特点

一个抽象类中可以存在多个抽象方法。在抽象类中可以定义非抽象方法。子类必须要重写父类中的所有抽象方法(非抽象方法不需要),否则会报错。如果子类不想重写父类的抽象方法,需要将子类也变成抽象类,即用abstract修饰。抽象类必须要用子类来实例化,即需要通过子类来创建对象。

抽象类可以定义有参/无参构造方法,用于子类访问父类初始化,即可以给父类的成员属性赋值。创建对象时,默认调用父类的无参构造方法。

18.3 案例

需求:假如我们在开发一个系统时需要对员工(Employee)类进行设计,员工包含3个属性:姓名、工号(number)、工资(salary)。经理(Manager)也是员工,除了有员工的属性外,还有一个奖金(bonus)属性。组长(headman)也是员工。然后定义工作的方法,请使用继承的思想设计出员工类和经理类。代码如下:

//第一个类Employee
public abstract class Employee {
    //定义成员属性
    private String name;
    private int number;
    private Double salary;

    //创建有参构造方法
    public Employee(String name, int number, Double salary) {
        this.name = name;
        this.number = number;
        this.salary = salary;
    }

    //不同员工的工作方法不同,因此用抽象方法
    public abstract void work();

    //getter/setter方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }
}


//第二个类Manager
public class Manager extends Employee{
    private int bonus;

    public Manager(String name, int number, Double salary,int bonus) {
        super(name, number, salary);
        this.bonus = bonus;
    }

    @Override
    public void work() {
        System.out.println("我是经理,我有管理工作");
    }

    public int getBonus() {
        return bonus;
    }

    public void setBonus(int bonus) {
        this.bonus = bonus;
    }
}


//第三个类Headman
public class Headman extends Employee{
    public Headman(String name, int number, Double salary,int subsidy) {
        super(name, number, salary);
    }
    @Override
    public void work() {
        System.out.println("我是组长,我有带领工作");
    }
}


//第四个类Test1(主方法)
public class Test1 {
    public static void main(String[] args) {
        Employee em1 = new Manager("小军",1, 2000.0,55);
        em1.work();
        System.out.println("姓名:"+em1.getName());
        System.out.println("工号:"+em1.getNumber());
        System.out.println("工资:"+em1.getSalary());
        //bonus在父类中没有,因此要向下转型,以免报错
        Manager em11 = (Manager) em1;
        System.out.println("奖金:"+em11.getBonus());
    }
}

18.4 abstract不能与哪些关键字共存?

答:private、final、static。因为被private修饰的方法无法被继承;被final修饰的的方法无法被继承且变量无法修改;被static修饰的方法为静态方法,需要通过“类名.方法名”访问方法体,而abstract修饰的方法是没有方法体的,冲突了。

 

19.接口

19.1 概念

接口就是一种公共的规范标准,只要符合标准,大家都可以通用。Java中的接口更多的体现在对行为的抽象。格式:①接口,用关键字interafce修饰,如 public interface 接口名{}。②类实现接口,用implements表示,如public class 类名 implements 接口{}。③接口不能实例化,怎么实现实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态。多态的形式有:具体类多态、抽象类多态、接口多态。接口的实现类,要么重写接口中所有的抽象方法,要么是抽象类。

19.2 接口成员特点

①成员变量只能是常量(即变量不能修改),默认有修饰符 public static final修饰,这3个关键字不用再写,例如:定义一个年龄变量:int age = 20 ; ②成员方法只能是抽象方法,默认有修饰符 public abstract修饰,因此这2个关键字不用写,例如:定义一个吃方法:void eat( ); 如果想在接口中定义非抽象方法,可以使用default关键字(JDK8开始才支持),例如:public default void show(){ } ; ③接口中没有构造方法(抽象类中有),因为接口主要对行为进行抽象,没有具体存在,一个类如果没有父类,默认继承自Object类。

19.3 案例--猫和狗

需求:对猫和狗进行训练,加入跳高功能,请采用抽象类和接口来实现。

思路:①定义跳高接口,成员方法:跳高();②定义动物类抽象类实现跳高接口,成员变量:姓名、年龄;构造方法:get/set方法,eat()方法;③定义猫类,继承动物类,构造方法:无参、有参;成员方法:重写eat(),重写跳高()方法;④定义狗类,继承动物类,构造方法:无参、有参,成员方法:重写eat(),重写跳高()。代码如下:

//定义一个接口
public interface JumpInterface {
    void jump();
}

//定义Animal抽象类
public abstract class Animal implements JumpInterface{
    //定义成员属性
    private int age;
    private String name;
    //有参构造方法
    public Animal(int age, String name) {
        this.age = age;
        this.name = name;
    }
    //无参构造方法
    public Animal() {

    }

    //吃方法
    public abstract void eat();

    //getter/setter方法
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

//定义Cat类
public class Cat extends Animal{
    //无参构造方法
    public Cat(){

    }
    //有参构造方法
    public Cat(int age, String name) {
        super(age, name);
    }

    @Override
    public void eat() {
        System.out.println("我是猫类,喜欢吃鱼");
    }

    @Override
    public void jump() {
        System.out.println("我是猫类,我可以跳高了");
    }
}
//定义狗类
public class Dog extends Animal{

    @Override
    public void eat() {
        System.out.println("我是狗类,喜欢吃骨头");
    }

    @Override
    public void jump() {
        System.out.println("我是狗类,可以跳高了");
    }
}

//定义AnimalDemo类(主方法)
public class AnimalDemo {
    public static void main(String[] args) {
        //编译看左边,执行看右边
        JumpInterface cat = new Cat(2,"小白");
        cat.jump();
        System.out.println("--------");
        Cat cat2 = new Cat(3,"小花");
        System.out.println(cat2.getName()+","+cat2.getAge());
        cat2.jump();
        cat2.eat();
        System.out.println("---------");
        JumpInterface dog = new Dog();
        dog.jump();
        Dog dog2 = new Dog();
        dog2.setAge(2);
        dog2.setName("小黑");
        dog2.eat();
        System.out.println(dog2.getName()+","+dog2.getAge());
    }
}

19.4 类和接口的联系

①类和类的继承关系:一个类只能单继承一个父类。

②类和接口的实现关系:一个类可以实现多个接口。

③接口和接口继承的关系:一个接口可以继承多个不同接口。

19.4 抽象类和接口的区别

抽象类是对事物的抽象,接口是对行为的抽象。

19.5 实例

①思路如下:

 

②实例代码如下:

//Door类
public abstract class Door {
    private int height;
    private int width;
    public abstract void open();
    public abstract void close();

    public Door(int height, int width) {
        this.height = height;
        this.width = width;
    }
}

//Alarm接口
public interface Alarm {
    void alarm();
}

//PanPanDoor类
public class PanPanDoor extends Door implements Alarm{

    public PanPanDoor(int height, int width) {
        super(height, width);
    }

    @Override
    public void alarm() {
        System.out.println("这是盼盼门,有报警功能");
    }

    @Override
    public void open() {
        System.out.println("这是盼盼门,有开门功能");
    }

    @Override
    public void close() {
        System.out.println("这是盼盼门,有关门功能");
    }
}

//MeiXinDoor类
public class MeiXinDoor extends Door{

    public MeiXinDoor(int height, int width) {
        super(height, width);
    }

    @Override
    public void open() {
        System.out.println("这是美兴门,有开门功能");
    }

    @Override
    public void close() {
        System.out.println("这是美兴门,有关门功能");
    }
}

//Test类(主方法)
public class Test {
    public static void main(String[] args) {
        PanPanDoor door1 = new PanPanDoor(200,100);
        door1.open();
        door1.close();
        door1.alarm();

        System.out.println("---------");
        MeiXinDoor door2 = new MeiXinDoor(200,150);
        door2.open();
        door2.close();
    }
}

 

20.内部类

20.1 概念

在一个类中定义的类,就叫内部类。

20.2 特点

①在内部类中,可以直接访问外部类的成员属性,包括private。②外部类也可以使用内部类的方法,先new 内部类,再通过“内部类对象引用.内部类方法”来调用。实例代码如下:

//MayiktA类
public class MayiktA {//外部类
    private int age = 22;
    public int height = 170;
    public class MayiktB{//内部类
        public void mayiktB(){
            System.out.println("我是内部类的B方法: "+age+","+height);
        }
    }

    //调用内部类的方法
    public void mayiktA(){
        MayiktB mayiktB = new MayiktB();
        mayiktB.mayiktB();
    }

}

//Test类(主方法)
public class Test {
    public static void main(String[] args) {
        MayiktA m = new MayiktA();
        m.mayiktA();
    }
}

20.3 内部类的分类

内部类大体上可分为“成员内部类”和“局部内部类”。如果要细分的话,成员内部类、方法内部类(局部内部类)、静态内部类、匿名内部类。

区别在哪呢?如果类定义在方法里面,该类就是方法内部类或局部内部类。如果类定义在方法外面,该类就更成员内部类,如果还用static修饰,该类就是静态内部类。

如何在外界类访问外部类中的内部类呢?格式为:外部类.内部类 变量名 = new 外部类().内部类(); 但实际企业开发中,不会让外界直接访问内部类,会使用private保证数据的安全性。可以采取在该类中写方法来间接访问内部类。

本类中的外部类想要访问内部类,则该内部类必须是静态。如下代码:

public class MayiktA {
    public static class MayiktB{
        //该类必须是静态的
        public void mayiktB(){
            System.out.println("内部类的方法");
        }
    }

    public static void main(String[] args) {
        //这是外部类,此处调用内部类
        MayiktB mayiktB = new MayiktB();
        mayiktB.mayiktB();
    }
}

外界类中想要访问内部类,则使用“外部类.内部类 = new 外部类.内部类()”格式。如下代码:

public class Test {
    public static void main(String[] args) {
        //使用“外部类.内部类 = new 外部类.内部类()”格式即可
        MayiktA.MayiktB mayiktA = new MayiktA.MayiktB();
    }
}

有static关键字修饰的内部类为静态内部类。静态内部类访问外部类的成员变量或方法,也必须是静态的。代码如下:

public class MayiktA {
	//成员变量
    private static int code = 22;
    public static void show(){
        System.out.println("这是外部类的静态成员方法");
    }
    
    //静态内部类
    public static class MayiktB{
        public void mayiktB(){
            System.out.println("内部类的方法");
            System.out.println(code);
            show();
        }
    }
}

局部内部类中的方法,只能在该方法里面访问,不能在方法外面访问。但是外面的成员方法,可以被内部类访问。

public class MayiktA {
    public void mayiktA(){
        // 定义局部内部类
        class MayiktB {
            public void mayiktB(){
                System.out.println("我是局部内部类的 mayiktB 方法");
            }
        }
        MayiktB mayiktB = new MayiktB();
        mayiktB.mayiktB();
    }
    //show()方法中调用mayiktB()方法会报错,因为无法访问
    public void show(){
        MayiktB mayiktB = new MayiktB();
        mayiktB.mayiktB();
    }
}

匿名内部类可以new接口(实现类)或抽象类(子类)。本质是一个继承了该类(子类)或者实现了该接口(实现类) 的匿名对象。

使用了匿名内部类后,就不需要创建“实现类”和“子类”了,因为直接通过new内部类的形式进行了简化。

//创建接口MayiktB
public interface MayiktB {
    void mayiktB();
}

//创建一个Test类(主方法)
public class Test {
    public static void main(String[] args) {
        MayiktB mayiktB = new MayiktB() {
            @Override
            public void mayiktB() {
                System.out.println("我是匿名内部类的 mayiktB方法");
            }
        };
        mayiktB.mayiktB();
    }
}

匿名内部类应用场景—不需要创建子类来重写父类方法

//创建一个动物抽象类(父类)
public abstract class AnimalParent {
    public abstract void eat();//创建抽象吃方法
}

//在Test类中调用
public class Test {
    public static void main(String[] args) {
        AnimalParent dog = new AnimalParent() {
            @Override
            public void eat() {
                System.out.println("我是狗类,喜欢吃骨头");
            }
        };
        AnimalParent cat = new AnimalParent() {
            @Override
            public void eat() {
                System.out.println("我是猫类,喜欢吃鱼");
            }
        };
        AnimalParent man = new AnimalParent() {
            @Override
            public void eat() {
                System.out.println("我是人类,喜欢吃米饭");
            }
        };
        dog.eat();
        cat.eat();
        man.eat();
    }
}

 

注意:接口和抽象类都不能实例化,而匿名内部类能实例化是因为其底层帮助创建了名称为null的实现类,这一过程是在编译阶段完成的。

© 版权声明
THE END
点赞0
相关推荐
评论 抢沙发
头像
这里需要一条查重率0%的评论!
提交
头像

昵称

取消
昵称表情

    暂无评论内容