day10 封装和继承

封装和继承

1. super关键字

super关键字来访问父类的成员

super只能出现在子类的方法和构造方法中

super调用构造方法时,只能是第一句

super不能访问父类的private成员

2.继承条件下的构造方法

继承条件下构造方法的调用规则

子类构造方法没有通过super显式调用父类的有参构造方法,也没通过this显式调用自身其他构造方法

系统默认调用父类的无参构造方法

子类构造方法通过super显式调用父类的有参构造方法

执行父类相应构造方法,而不执行父类无参构造方法

子类构造方法通过this显式调用自身的其他构造方法,在相应构造方法中应用以上两条规则

3. 子类可以继承父类哪些内容

子类继承父类的什么?

继承public和protected修饰的属性和方法,不管子类和父类是否在同一个包里

继承默认权限修饰符修饰的属性和方法,但子类和父类必须在同一个包里

private修饰的属性和方法不能被继承

4. 子类不能继承父类哪些内容

不能继承内容

5. 什么时候用继承?

何时使用继承?

继承与真实世界类似

只要说“猫是哺乳动物”,猫的很多属性、行为就不言自明了

藏獒是一种狗

继承是代码重用的一种方式

子类与父类符合is-a的关系 使用继承描述

将子类共有的属性和行为写在父类中

子类独有的属性和行为写在子类中

6. static关键字

static关键字实现原理:

1.对象的创建过程

​ 1.1 先将当前对象对应类信息文件加载到方法区,随后初始化静态相关的信息

​ 加载之前先检查类信息文件是否已经被加载,如果没有被加载则加载,如果加载过,不再重复加载

类信息文件只加载一次/类只加载一次

​ 1.2 在堆中开辟空间 此时实例属性有默认值

​ 1.3 将堆中的地址赋值给栈中的引用 完成对象的创建

2.名词解释 方法区 永久代 元数据区

​ 方法区属于SUN公司制定的一个规范 举例:JVM是一个规范 hotspot是JAVA默认具体虚拟机名称

​ JDK1.7之前称之为永久代

​ JDK1.8改名为元数据/元空间

6.1 修饰属性

被static修饰的属性 称之为静态变量 内存中只存在一份 不属于任何对象 属于整个类 可以被当前类所有对象共享

静态变量不推荐使用通过对象(对象名加点)访问 推荐使用访问方式:

1.本类中直接访问

2.其他类通过类名加点访问

静态变量和实例变量区别、?

类变量(静态变量)
被static修饰的变量
在内存中只有一个拷贝
类内部,可在任何方法内直接访问静态变量
其他类中,可以直接通过类名访问

实例变量
没有被static修饰的变量
每创建一个实例,就会为实例变量分配一次内存,实例变量在内存中有多个拷贝,互不影响

package com.atguigu.test1;

/**
 * static 修饰属性/成员变量/实例变量/字段
 *      被static修饰的属性 称之为静态变量 内存中只存在一份
 *      不属于任何对象 属于整个类 可以被当前类所有对象共享
 *
 * 属性:当某个字段拥有了get以及set方法 才可以被称之为属性
 * 字段:直接写在类中的变量 就是字段
 * */

public class Student {
    String name;
    int age;
    static String gradeName = "三年二班";

    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.name = "赵四";
        stu1.age = 20;

        stu1.gradeName = "3年3班";  // stu1中修改静态属性,其他对象也会同步
        System.out.println(stu1.gradeName);  // 3年3班

        Student stu2 = new Student();
        stu2.name = "广坤";
        stu2.age = 21;

        System.out.println(stu2.gradeName);  // 3年3班

        Student stu3 = new Student();
        stu3.name = "大拿";
        stu3.age = 22;

        System.out.println(stu3.gradeName);  // 3年3班

        // 1.以上三个对象相互之间有没有关系?
        // 有关系:这三个对象都源自于同一个类所创建
        // 没有关系:这三个对象在内存中 有三块独立的空间 相互之间不影响

        // 因为这三个对象在内存中属于独立的内存空间 属性都属于实例级别的
        // 每创建一个对象 就会在内存中存在一份 所以如果多个对象有共同的属性值 那么每次创建都会重复赋值一份 比较浪费内存空间
        // 推荐做法:将多个对象共同使用的属性值 设置为静态级别的 内存中只存在一份
        // 不属于任何对象 属于整个类 可以被当前类所有对象共享

    }
}

package com.atguigu.test1;
/**
 * 使用static关键字模拟 饮水机饮水过程
 * */

public class DrinkWater {
    static int capacity = 100;  // 单位 L
    String name;

    public void getWater(){
        if (capacity > 0){
            capacity -= 2;
            System.out.println(name + "接水2L,还剩余" + capacity + "L");
        }else{
            System.out.println("没水了");
        }
    }

    public static void main(String[] args) {
        DrinkWater zs = new DrinkWater();
        zs.name = "赵四";
        zs.getWater();  // 赵四接水2L,还剩余98L

        DrinkWater dn = new DrinkWater();
        dn.name = "大拿";
        dn.getWater();  // 大拿接水2L,还剩余96L

        DrinkWater gk = new DrinkWater();
        gk.name = "广坤";
        gk.getWater();  // 广坤接水2L,还剩余94L
    }
}

6.2 修饰方法

static修饰方法:本类中直接访问 其他类 通过类名访问

package com.atguigu.test3;
/**
 * static修饰方法:本类中直接访问 其他类 通过类名访问
 * */
public class Test1 {
    public static void m1(){
        System.out.println("static修饰的m1方法");
    }

    public static void main(String[] args) {
        m1();
    }
}

class A{
    public static void main(String[] args) {
        Test1.m1();  // static修饰的m1方法
    }
}

6.3 修饰代码块

static修饰代码块 :静态代码块 随着类的加载而执行 多个静态代码块 按照书写顺序执行

每个只执行一次 因为类只加载一次

什么时候加载类?

1.new对象

2.访问当前类中的静态信息

什么使用时候静态代码块?

静态代码块中通常用于数据初始化操作 或者 执行一切前置的必要操作

总结:只需要执行一次 而且必须提前完成

package com.atguigu.test3;
/**
 * static修饰代码块:静态代码块 随着类的加载而执行 多个静态代码块 按照书写顺序执行
 * 每个只执行一次 因为类只加载一次
 *
 * 什么时候加载类?
 *      1.new对象
 *      2.访问当前类中的静态信息
 *
*  什么时候使用静态代码块?
 *      静态代码块中通常用于数据初始化操作 或者 执行一些前置的必要操作
 *      总结:只需要执行一次 而且必须提前完成
 * */
public class Test2 {
    static int num;  // 默认值为0
    int age;
    static {
        System.out.println("静态代码块1");
    }

    static {
        System.out.println("静态代码块2");
    }

    static {
        System.out.println("静态代码块3");
    }

    public static void main(String[] args) {
        // 不管创建多个对象,静态代码块只会执行一次
//        Test2 t1 = new Test2();
//        Test2 t2 = new Test2();
//        Test2 t3 = new Test2();

        // 不管访问多少次静态信息,静态代码块只会执行一次
        System.out.println(num);  // 0
        System.out.println(num);  // 0
        System.out.println(num);  // 0
        System.out.println(num);  // 0


    }
}

普通代码块/实例代码块

随着对象的创建而执行 每创建一次对象就执行执行

package com.atguigu.test3;

/**
 * 普通代码块/实例代码块
 * 随着对象的创建而执行 每创建一次对象就执行一次
 * */
public class Test3 {
    static int num;

    {
        System.out.println("普通代码块1");
    }

    {
        System.out.println("普通代码块2");
    }

    public static void main(String[] args) {
        // 访问类属性不会执行普通代码块
        System.out.println(num);  // 0

        // 创建对象就会执行普通代码块的内容
        Test3 t1 = new Test3();
        System.out.println("-------------------");

        Test3 t2 = new Test3();
        System.out.println("-------------------");

        Test3 t3 = new Test3();
    }
}

7. 访问规则

静态与实例访问规则:

同级别互相直接访问 (实例访问实例 直接访问 静态访问静态 直接访问)

实例访问静态 直接访问 (因为可以访问实例的时候 肯定创建完对象 也就是说类肯定加载完了)

静态访问实例 先new对象 (再通过对象名加点访问)

在实例方法里不可以定义static变量

package com.atguigu.test4;
/**
 * 静态与实例访问规则:
 *  同级别互相直接访问 (实例访问实例 直接访问 静态访问静态 直接访问)
 *  实例访问静态 直接访问 (因为可以访问实例的时候 肯定是创建完对象了 也就是说类肯定加载完了)
 *  静态访问实例 先new对象(再通过对象名加点访问)
 * */

public class Test1 {
    String field1;
    static String field2;

    // 实例方法之间可以直接访问
    public void m1(){
        m3();
    }

    public void m2(){
        m1();
    }

    public void m3(){
        m2();
    }

    // 静态方法之间可以直接访问
    public static void m4(){
        m6();
    }

    public static void m5(){
        m4();
    }

    public static void m6(){
        m5();
    }


    public void test1(){
        // 实例方法中可以直接访问静态方法
        test2();
    }

    public static void test2(){
        // 静态方法中访问实例方法 需要先创建实例对象
        Test1 t1 = new Test1();
        t1.test1();
    }

    public static void main(String[] args) {

    }
}

8. static练习题

模拟实现选民投票过程:一群选民进行投票,每个选民只允许投一次票,

并且当投票总数达到100时,就停止投票

package com.atguigu.test5;

public class Test1 {
    String name;
    static int count;

    public Test1(String name){
        this.name = name;
    }

    public boolean addCount(){
        if (count < 100){
            count++;
            System.out.println(name + "投1票,当前投票总数为:" + count + "票");
            return true;
        }else{
            System.out.println("投票总数达到100,无需再投");
            return false;
        }
    }

    public static void main(String[] args) {
        Test1 t1 = new Test1("张三");
        t1.addCount();

        Test1 t2 = new Test1("李四");
        t2.addCount();

        for (int i = 1;i < 110;i++){
            Test1 t = new Test1(i + "号民众");
            if (!t.addCount()){
                break;
            }
        }
    }
}

9. 方法重写规则

方法重写

1.存在于父子类之间

2.方法名相同

3.参数列表相同

4.返回值相同 或者是其子类

5.访问权限不能严于父类 /不能窄化父类的访问权限

6.不能比父类抛出更多的异常

7.静态方法可以被继承 但是不能被重写

我们可以通过@Override注解实现正确的重写,此注解可以提高代码的阅读性

package com.atguigu.test6;

public class Pet {
    protected String name;
    protected int health;
    protected int love;

    public String getName() {
        return name;
    }

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

    public int getHealth() {
        return health;
    }

    public void setHealth(int health) {
        this.health = health;
    }

    public int getLove() {
        return love;
    }

    public void setLove(int love) {
        this.love = love;
    }

    void print(){
        System.out.println("宠物的名字是:" + name + ",健康值是:" + health);
        System.out.println("亲密值是:" + love);
    }

    public Pet(){}
}

package com.atguigu.test6;

public class Dog extends Pet{

    private String strain;

    public String getStrain(){
        return strain;
    }

    public void setStrain(String strain){
        this.strain = strain;
    }

    public void print(){
        System.out.println("狗狗的品种是:" + strain);
    }
}

package com.atguigu.test6;

public class TestPet {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.print();  // 狗狗的品种是:null
    }
}

10. 方法重写和方法重载区别

重写和重载

11.Object类

11.1 重写toString方法

Object类中经常被子类重写的方法

toString() :返回当前对象的信息 包名 + 类名 + hash值

1.为什么Student对象可以直接调用toString方法?

​ 答:因为是从Object类继承而来 所有的类默认继承自Object

2.为什么调用toString方法会出现包名 类名 hash值 ?

​ 答:因为Object类中就是这么实现的

3.为什么要重写toString方法?

​ 答:实际开发中,我们都会重写toString方法 用于输出当前对象的属性名 和 属性值

package com.atguigu.test7;

/**
 * Object类中经常被子类重写的方法
 *      toString():返回当前对象的信息 包名 + 类名 + hash值
 *
*  1.为什么Student对象可以直接调用toString方法?
 *      答:因为是从Object类继承而来 所有的类默认继承自Object
 * 2.为什么调用toString方法会出现包名 类名 hash值?
 *      答:因为Object类中就是这么实现的
 * */
public class Student {
    private String name;
    private int 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 toString(){
        return "Student[name = " + name + ", age = " + age + "]";
    }

    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.name = "赵四";
        stu1.age = 20;

        System.out.println(stu1.name);
        System.out.println(stu1.age);

        // ctrl + 鼠标左键进入源代码
        System.out.println(stu1.toString());  // 重写toString前打印 com.atguigu.test7.Student@1540e19d  重写toString后打印 Student[name = 赵四, age = 20]
        System.out.println(stu1);  // 打印对象地址 相当于调用此对象的toString方法

        Student stu2 = new Student();
        stu2.name = "大拿";
        stu2.age = 21;
        System.out.println(stu2);
    }
}

11.1 重写equals方法

重写Object类提供的equals方法

1.==和equals的区别?

答:==比较基本数据类型 比较的是值

==比较引用数据类型 比较的是地址

equals方法本身也比较地址 但是我们可以重写自定义比较规则 String类就是对equals进行了重写

2.equals方法本身的作用?

答:父类(Object)中equals方法本身用于比较两个对象的地址是否相同

3.String类使用的equals方法是怎样的效果?

答:String类中对父类Object类中的equals方法进行了重写 将原本的比较地址 重写为了比较内容

package com.atguigu.test8;
/**
 * 重写Object类提供的equals方法
 *
 * 1.==和equals的区别?
 *      答:==比较基本数据类型  比较的是值
 *         ==比较引用数据类型  比较的是地址
 *         equals方法本身也比较地址 但是我们可以重写自定义比较规则 String类就是equals进行了重写
 *
 * 2.equals方法本身的作用?
 *      答:父类(Object)中equals方法本身用于比较两个对象的地址是否相同
 *
 * 3.String类使用的equals方法是怎样的效果?
 *      答:String类中对父类Object类中的equals方法进行了重写 将原本的比较地址 重写为了比较内容
 * */

public class Person {
    String name;  // 名字
    String idCard;  // 身份证号

    public Person(){}

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

    public static void main(String[] args) {
        Person p1 = new Person("赵四", "12392347234235345");
        Person p2 = new Person("赵四", "12392347234235345");

        System.out.println(p1 == p2);  // false
        System.out.println(p1.equals(p2));  // false

        String str1 = new String("abc");
        String str2 = new String("abc");

        System.out.println(str1 == str2);  // false
        System.out.println(str1.equals(str2));  // true
    }
}

模拟String类equals方法书写myEquals方法

package com.atguigu.test8;

/**
 * 模拟String类equals方法书写myEquals方法
 * */
public class MyString {
    public static void main(String[] args) {
        String str1 = "abc";

        char[] ch1 = str1.toCharArray();

        for (int i = 0;i < ch1.length;i++){
            System.out.print(ch1[i] + "\t");  // a	b	c
        }
        System.out.println();

        String str2 = "hello world";
        String str3 = "hello world";
        String str4 = "hello word!";

        System.out.println(myEquals(str2, str3));  // true
        System.out.println(myEquals(str2, str4));  // false


    }

    public static boolean myEquals(String str1, String str2){
        if (str1 == str2){
            return true;
        }

        char[] ch1 = str1.toCharArray();
        char[] ch2 = str2.toCharArray();

        if (ch1.length != ch2.length){
            return false;
        }

        for (int i = 0;i < ch1.length;i++){
            if (ch1[i] != ch2[i]){
                return false;
            }
        }

        return true;
    }


}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值