java包、封装、继承动态绑定机制、==和equals

目录

idea常用快捷键

idea模板

包 

访问修饰符 

封装 (encapsulation)

继承

super关键字

方法重写 (override)

 多态

 instanceOf比较操作符

动态绑定机制 (很很很重要)

 == 和 equals 比较

hashCode方法 

toString方法 

finalize方法 

断点调试 (Debug)


本文内容使用IDEA集成开发工具,版本2020.2

idea常用快捷键

  1. 删除当前行,自己配置 ctrl + D (file-settings-keymap-delete line)
  2. 复制当前行,自己配置 ctrl + alt + 向下键
  3. 补全代码 alt + /
  4. 添加和取消注释 ctrl + /
  5. 导入该行所需的类,先配置auto import,配置后使用 alt + enter 即可
  6. 快速格式化代码 ctrl + alt + L
  7. 快速运行程序,自己配置 ctrl + R
  8. 生成构造器 alt + insert (常用)
  9. 查看一个类的层级关系 ctrl + H
  10. 定位到方法,光标移动到方法处,ctrl + B
  11. 自动分配变量名,在new 类型后输入.var回车

idea模板

file-settings-editor-Live Templates

如:

main:输入main回车可以快速补齐输出模板


包 

  • 作用
  1. 区分相同名字的类
  2. 类很多时方便管理
  3. 控制访问范围 
  • 包的本质 

实质上就是创建不同的文件夹来保存类

  • 包的命名规则 
  1. 只能包含数字、字母、下划线、小圆点,不能以数字开头
  2. 小圆点间隔的每个部分都要符合1的规则
  3. 一般由小写字母和小圆点组成 
  • 常用的包 
  1. java.lang.*        //lang是基本包,默认引入,无需额外引入
  2. java.util.*          //util包,系统提供的工具包,java.util.Scanner
  3. java.net.*          //网络包,网络开发
  4. java.awt.*         //java的界面开发,GUI
  • 包的使用细节 
  1. package用来声明当前类所在的包,位于类的最上面,一个类只能有一个package
  2. import导入包,位于package下面,类上面,可以有多个导入,无顺序

访问修饰符 

  1. public
  2. protected
  3. 默认
  4. private 

背!

  • 修饰符使用细节 

类的修饰符只能是 public 或 默认不写 


封装 (encapsulation)

隐藏实现细节,将抽象出的属性和方法封装起来

  • 封装的实现步骤 
  1. 将属性进行私有化
  2. 提供一个公共的set方法,用于对属性判断并赋值
  3. 提供一个公共的get方法,用于获取属性的值

public class Encapsulation01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("Lucy");
        person.setAge(21);
        person.setSalary(8000);
        System.out.println(person.info());

        Person person1 = new Person();
        person1.setName("L");
        person1.setAge(0);
        person1.setSalary(6000);
        System.out.println(person1.info());
    }
}

class Person {
    public String name;
    private int age;
    private double salary;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if(name.length() >= 2 && name.length() <= 6) {
            this.name = name;
        }else{
            System.out.println("名字长度应为2-6个字符,默认值为Lulu");
            this.name = "Lulu";
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age >= 1 && age <= 120){
            this.age = age;
        }else{
            System.out.println("年龄应在[1-120]内,给出默认值:18");
            this.age = 18;
        }
    }

    public double getSalary() {
        return salary;
    }

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

    public String info() {
        return "name = " + name + " age = " +
                age + " salary = " + salary;
    }
}

也可以将set方法写在构造器中,也可以验证

public Person(String name, int age, double salary) {
    setName(name);
    setAge(age);
    setSalary(salary);
}
  • 封装小练习 

public class Account {
    private String name;
    private String password;
    private double balance;

    public Account() {
    }

    public Account(String name, String password, double balance) {
        setName(name);
        setPassword(password);
        setBalance(balance);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if(name.length() >= 2 && name.length() <= 4) {
            this.name = name;
        }else {
            System.out.println("名字长度应该在2-4,默认值Lili");
            this.name = "Lili";
        }
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        if(password.length() == 6) {
            this.password = password;
        }else {
            System.out.println("密码长度应为6位,默认123456");
            this.password = "123456";
        }
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        if(balance >= 20) {
            this.balance = balance;
        }else {
            System.out.println("余额应该大于20,默认值10000");
            this.balance = 10000;
        }
    }

    public void showInfo() {
        System.out.println("name = " + name + " password = "
        + password + " balance = " + balance);
    }
}
public class TestAccount {
    public static void main(String[] args) {
        Account account = new Account("l", "111111", 10);
        account.showInfo();
    }
}

继承

当多个类存在多个相同的属性和方法时,就可以抽象出一个父类,实现代码复用 ,所有子类不需要重新定义这些方法,只需extends父类

  • 基本语法

class 子类名 extends 父类名 {

}

  •  继承细节
  1. 父类的非私有属性和方法可以在子类直接访问,私有属性和方法只能通过父类的共有方法来访问
  2. 子类必须调用父类的构造器,完成父类的初始化 
  3. 创建子类对象时,不管使用子类的哪个构造器,默认都要调用父类的无参构造器,若父类没有无参构造器,则必须指定一个父类构造器,否则报错
  4. 指定调用父类构造器,super(形参列表)
  5. super()必须位于构造器内第一行
  6. super()和this()都必须位于第一行,所以两个方法不能共存在一个构造器
  7. java所有类都是object的子类
  8. 父类构造器的调用将一直层层追溯到object类
  9. 子类最多只能继承一个父类

super关键字

super用于访问父类的属性、方法和构造器,但不能访问父类private的属性和方法。 

  • 细节 
  1. 调用父类构造器好处:父类属性可以由父类初始化,子类属性由子类初始化
  2. 当子类中的属性或方法与父类的重名时,像调用父类的必须用super关键字,若没有重名,super等价于this 


方法重写 (override)

  1. 方法重写也叫方法覆盖,是指子类的方法名、参数列表和父类完全一样
  2. 子类方法的返回类型和父类的一样,或是父类返回类型的子类 
  3. 子类方法不能缩小父类的返回权限(public>protected>默认>private)

  • 方法重写小练习 

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String say() {
        return "name = " + name + " age = " + age;
    }
}
public class Student extends Person{
    private int id;
    private double score;

    public Student(String name, int age, int id, double score) {
        super(name, age);
        this.id = id;
        this.score = score;
    }

    @Override
    public String say() {
        return "Student " + super.say() + " id = "
                + id + " score = " + score;
    }
}
public class TestOverride {
    public static void main(String[] args) {
        Person june = new Person("june", 21);
        Student july = new Student("July", 20, 11, 98.5);
        System.out.println(june.say());
        System.out.println(july.say());
    }
}


 多态

方法和对象具有多种形态

  • 方法的多态,重写和重载体现多态
  • 对象的多态 
  1.  一个对象的编译类型和运行类型可以不一致⭐⭐
  2. 编译类型在定义对象的时候就确定了,不能改变
  3. 运行类型可以变化
  4. 编译类型看定义时=号的左边,运行类型看=号的右边

多态细节

  • 多态的前提是两个类存在继承关系
  • 多态的向上转型
  1. 父类的引用指向了子类的对象
  2. 基本语法:父类类型 引用名 = new 子类类型();
  3. 特点:编译类型看左边,编译类型看右边
  4. 可以调用父类的所有成员,不能调用子类的特有成员,因为编译类型是父类,没有子类的特有方法
  •  多态的向下转型
  1. 基本语法:子类类型 引用名 = (子类类型) 父类引用;
  2. 只能强转父类的引用,不能强转父类的对象
  3. 要求父类的引用必须指向当前要转型的子类类型的对象
  4. 可以调用子类类型的所有成员
  •  属性没有重写之说,属性的值看编译类型⭐⭐
public class PolyDetail {
    public static void main(String[] args) {
        Base base = new Sub(); //向上转型
        System.out.println(base.count); //编译类型为Base,count = 10
        Sub sub = (Sub)base; //向下转型
        System.out.println(sub.count);// 编译类型为Sub,count = 20
    }
}

class Base {
    int count = 10;
}

class Sub extends Base{
    int count = 20;
}

 instanceOf比较操作符

用于判断某类型是否为xx类型或xx类型的子类型

  • instanceOf 看的是运行类型 
public class PolyDetail02 {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        System.out.println(a1 instanceof A); //true
        System.out.println(a1 instanceof B); //false
        System.out.println(a2 instanceof B); //true
    }
}

class A {
}

class B extends A{
}

 小练习

 

 


动态绑定机制 (很很很重要)

  1.  当调用对象方法时,方法会和对象的内存地址即运行类型绑定
  2. 对象属性没有动态绑定机制,哪里声明,哪里使用

下面两段代码值得好好思考~ 

package com.lili.poly_;

public class Dynamic {
    public static void main(String[] args) {
        AA aa = new BB();
        System.out.println(aa.sum()); //40
        System.out.println(aa.sum1()); //30
    }
}

class AA {
    public int i = 10;
    public int sum() {
        return getI() + 10;
    }
    public int sum1() {
        return i + 10;
    }
    public int getI() {
        return i;
    }
}

class BB extends AA {
    public int i = 20;
    public int sum() {
        return i + 20;
    }
    public int sum1() {
        return i + 10;
    }
    public int getI() {
        return i;
    }
}
package com.lili.poly_;

public class Dynamic {
    public static void main(String[] args) {
        AA aa = new BB();
        System.out.println(aa.sum()); //30
        System.out.println(aa.sum1()); //30
    }
}

class AA {
    public int i = 10;
    public int sum() {
        return getI() + 10;  //BB类没有sum方法,往父类AA来找,这里的getI方法有动态绑定,调用的是BB的getI
    }
    public int sum1() {
        return i + 10;
    }
    public int getI() {
        return i;
    }
}

class BB extends AA {
    public int i = 20;
//    public int sum() {
//        return i + 20;
//    }
    public int sum1() {
        return i + 10;
    }
    public int getI() {
        return i;
    }
}

思考,如果把BB类的sum1方法也注释了,会输出什么?  


 多态数组

数组的定义类型为父类类型,里面保存的元素类型可以为父类或子类


多态参数

方法定义的形参类型为父类,实参可以是它的子类


 == 和 equals 比较

  1. == 既可以判断基本类型,又可以判断引用类型
  2. == 判断基本类型时,判断的是值是否相等 
  3. == 判断引用类型时,判断的是是否是同一个对象,也可以说是否指向同一地址
  4. equals 是Object 的方法,只能判断引用类型
  5. Object 子类String 和 Integer 重写了equals方法,判断时值相等就相等

hashCode方法 

  1. 提高具有hashCode结构的容器的效率
  2. 两个引用如果指向同一个对象,hashCode值一定是一样的
  3. 两个引用如果指向不同对象,hashCode值不一样
  4. hashCode值是根据地址得到的,但hashCode值不完全等同于地址

toString方法 

  1. 默认返回:全类名 + @ + 哈希值的十六进制,Object的子类往往会重写 toString 方法 
  2. 当直接输出一个对象时,toString方法会默认被调用

finalize方法 

  1. 当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作
  2.  什么时候被回收,当某个对象没有任何引用时,jvm认为这个对象是一个垃圾对象,就会使用垃圾回收机制销毁该对象,在销毁该对象前会调用finallize方法
  3. 垃圾回收机制的调用由系统决定,也可以通过System.gc()主动触发垃圾回收机制

断点调试 (Debug)

  •  F8逐行执行
  • F7跳入方法内部,光标放到某个变量上,可以看到当前值

  • 断点可以在Debug的过程中,动态的下断点 

  • 20
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lili_1i1i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值