3.面向对象中级

区分相同名字的类,控制访问范围

基本语法:package 包名

包的本质,实际上就是 创建不同的文件夹 / 目录来保存类文件 \textcolor{green}{创建不同的文件夹/目录来保存类文件} 创建不同的文件夹/目录来保存类文件

包的命名:只能是 数字,字母,下划线,小圆点 , 不能用数字开头,不能是关键字或保留字 \textcolor{blue}{数字,字母,下划线,小圆点,不能用数字开头,不能是关键字或保留字} 数字,字母,下划线,小圆点,不能用数字开头,不能是关键字或保留字

​ 一般 公司名.项目名.业务模块

image-20230819125008089

package com.use //这句话的意思想当与下面的内容都在com.use包下面,
                //必须放在第一行,一个类且只能放在一个包下,包下可以有多个类
import com.lin * //表示引入com.lin包下的所有类(不推荐),impor语句放在package下,类定义之前
import com.xiaoqiang.Dog//表示引入com.xiaoqiang包下的Dog类,一般来讲,用哪个就导入哪个
//import com.xiaohua.Dog; 错误
//编译器只能引用一个Dog类,这里会报错,要想使用xiaohua.Dog,创建的时候添加包名  
public class Test{
    public static void main(String[] args){
        com.xiaoqiang.Dog dog=new com.xiaoqiang.Dog();
        System.out.println(dog);
        
        com.xiaohua.Dog dog1=new com.xiaohua.Dog();
        System.out.println(dog);
        
    }
}    

访问修饰符

用于控制方法和属性的访问权限,也可以修饰类,但是只有 p u b l i c 和默认 \textcolor{blue}{用于控制方法和属性的访问权限,也可以修饰类,但是只有public和默认} 用于控制方法和属性的访问权限,也可以修饰类,但是只有public和默认

    1.public:对外公开

    2.protected:对子类同一个包中的类公开

    3.默认:没有修饰符,向同一个包中的类公开

    4.private:只有类本身可以访问,不对外公开

封装

封装把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(方法),才能对数据进行操作;

     1. 隐藏实现细节 \textcolor{blue}{1.隐藏实现细节} 1.隐藏实现细节

     2. 可以对数据进行验证 \textcolor{blue}{2.可以对数据进行验证} 2.可以对数据进行验证

实现步骤:

​      1.将属性进行私有化private(不能直接修改属性)

​      2.提供一个公共public的set方法,用于对属性的判断修改x

            public void setXxx(类型名 参数名){
                                //数据验证
                                属性=参数名;
                         }

     3.提供一个公共public的get方法,用于获取属性的值
            public XX getXxx(){
                    return xx;
                }

package com.hspedu.encap;

public class Encapsulation01 {

    public static void main(String[] args) { 
        Person person = new Person();
        person.setName("韩顺平");
        person.setAge(30);
        person.setSalary(30000);
        System.out.println(person.info());
        System.out.println(person.getSalary());

        //如果我们自己使用构造器指定属性
        Person smith = new Person("smith", 80, 50000);
        System.out.println("====smith的信息======");
        System.out.println(smith.info());
    }
}
/*
不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认
年龄, 必须在 1-120, 年龄, 工资不能直接查看 , name的长度在 2-6字符 之间
 */
class Person {
    public  String name; //名字公开
    private int age; //age 私有化
    private double salary; //..私有化

    public void say(int n,String name) {

    }
    //构造器 alt+insert
    public Person() {}
    //有三个属性的构造器
    public Person(String name, int age, double salary) {
//        this.name = name;
//        this.age = age;
//        this.salary = salary;
        //我们可以将set方法写在构造器中,这样仍然可以验证
        setName(name);
        setAge(age);
        setSalary(salary);
    }

    //自己写setXxx 和 getXxx 太慢,我们使用快捷键alt+insert
    //然后根据要求来完善我们的代码.
    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)个字符,默认名字");
            this.name = "无名人";
        }
    }

    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;
    }
}

继承

继承可以解决代码复用,当 多个类存在相同属性和方法时,可以从这些类中抽象出父类 \textcolor{blue}{多个类存在相同属性和方法时,可以从这些类中抽象出父类} 多个类存在相同属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类

继承基本语法:
​         class 子类 extends 父类{
​             }

image-20230819140531634

public class Extends01 {
    public static void main(String[] args) {
        Pupil pupil = new Pupil();
        pupil.name = "银角大王~";
        pupil.age = 11;
        pupil.testing();
        pupil.setScore(50);
        pupil.showInfo();

        System.out.println("=======");
        Graduate graduate = new Graduate();
        graduate.name = "金角大王~";
        graduate.age = 23;
        graduate.testing();
        graduate.setScore(80);
        graduate.showInfo();
    }
}
class Student { //父类
    //共有属性
    public String name;
    public int age;
    private double score;//成绩
    //共有的方法
    public void setScore(double score) {
        this.score = score;
    }

    public void showInfo() {
        System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
    }
}

class Pupil extends Student {//继承父类的子类
    public void testing() {
        System.out.println("小学生 " + name + "  正在考小学数学..");
    }
}

class Graduate extends Student {//继承父类的子类

    public void testing() {//和Pupil不一样
        System.out.println("大学生 " + name + " 正在考大学数学..");
    }
}

继承使用细节

1.子类继承了父类所有的属性和方法 非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类 \textcolor{blue}{非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类} 非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类

直接访问。要通过父类提供公共的方法去访问 \textcolor{blue}{直接访问。要通过父类提供公共的方法去访问} 直接访问。要通过父类提供公共的方法去访问

2.子类必须调用父类的构造器,完成父类的初始化。

3.当创建子类对象时,不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器。 \textcolor{blue}{默认情况下总会去调用父类的无参构造器。} 默认情况下总会去调用父类的无参构造器。如果父类 没有 \textcolor{blue}{没有} 没有提供无参构造器, 则必须在子类的构造器中使用 s u p e r 去指定使用父类的哪个构造器完成对父类的初始化工作, \textcolor{blue}{则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,} 则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不会通过。

4.如果希望指定去调用父类的某个构造器,则显式的调用一下:super()

5.supper在使用时需要放在构造器第一行

6. s u p p e r ( ) 和 t h i s ( ) 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。 \textcolor{blue}{supper()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。} supper()this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。

7.JAVA所有类都是Object 类的子类

8.父类构造器的调用不限于直接父类,将一直往上追溯到Object类。

9.子类最多 只能继承一个父类,但可以 A 继承 B , B 继承 C ,这样相当于 A 继承了 B , C \textcolor{blue}{只能继承一个父类,但可以A继承B,B继承C,这样相当于A继承了B,C} 只能继承一个父类,但可以A继承BB继承C,这样相当于A继承了BC

public class ExtendsDetail {
    public static void main(String[] args) {
//        System.out.println("===第1个对象====");
//        Sub sub = new Sub(); //创建了子类对象 sub
//        System.out.println("===第2个对象====");
//        Sub sub2 = new Sub("jack"); //创建了子类对象 sub2
        System.out.println("===第3对象====");
        Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2
        //sub.sayOk();
    }
}
class TopBase { //父类是Object

    public TopBase() {
        //super(); Object的无参构造器
        System.out.println("构造器TopBase() 被调用...");//1
    }
}

class Base extends TopBase { //父类
    //4个属性
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public Base() { //无参构造器
         //默认super()
        System.out.println("父类Base()构造器被调用....");
    }
    public Base(String name, int age) {//有参构造器
        //默认super()
        System.out.println("父类Base(String name, int age)构造器被调用....");
    }
    public Base(String name) {//有参构造器
         //默认super()
        System.out.println("父类Base(String name)构造器被调用....");
    }
    
    //父类提供一个public的方法,返回了n4
    public int getN4() {return n4;}
    
    
    public void test100() {System.out.println("test100");}
    protected void test200() {System.out.println("test200");}
    void test300() {System.out.println("test300");}
    private void test400() {System.out.println("test400");}
    //父类提供一个public的方法,返回了test400()
    public void callTest400() {test400(); }
}
class Sub extends Base { //子类

    public Sub(String name, int age) {
        //1. 调用父类的无参构造器, 如下或者什么都不写,默认就是调用super()
        //super();//父类的无参构造器
        //2. 调用父类的 Base(String name) 构造器
        //super("hsp");
        //3. 调用父类的Base(String name, int age) 构造器
        super("king", 20);

        //细节: super在使用时,必须放在构造器第一行
        //细节: super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
        //this() 不能再使用了
        System.out.println("子类Sub(String name, int age)构造器被调用....");


    }

    public Sub() {//无参构造器
        //super(); //默认调用父类的无参构造器
        super("smith", 10);
        System.out.println("子类Sub()构造器被调用....");
    }
    //当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
    public Sub(String name) {
        super("tom", 30);
        //do nothing...
        System.out.println("子类Sub(String name)构造器被调用....");
    }

    public void sayOk() {//子类方法
        //非私有的属性和方法可以在子类直接访问
        //但是私有属性和方法不能在子类直接访问
        System.out.println(n1 + " " + n2 + " " + n3);
        test100();
        test200();
        test300();
        //test400();错误
        //要通过父类提供公共的方法去访问
        System.out.println("n4=" + getN4());
        callTest400();//
    }

}

继承内存布局及细节

image-20230819145009821

public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();//内存的布局
        //?-> 这时请大家注意,要按照查找关系来返回信息
        //(1) 首先看子类是否有该属性或者方法
        //(2) 如果子类有这个属性,并且可以访问,则返回信息;如果不能访问,就报错
        //(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
        //(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object...
        System.out.println(son.name);//返回就是大头儿子
        //System.out.println(son.age);//因为39是private,会报错
        //System.out.println(son.getAge());//返回的就是39,通过公共的方法访问私有属性
        System.out.println(son.hobby);//返回的就是旅游
    }
}

class GrandPa { //爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}

class Father extends GrandPa {//父类
    String name = "大头爸爸";
    private int age = 39;
    public int getAge() {
        return age;
    }
}
class Son extends Father { //子类
    String name = "大头儿子";
}

Super

super代表父类的引用,用于访问 父类的属性,方法,构造器 \textcolor{blue}{父类的属性,方法,构造器} 父类的属性,方法,构造器

super使用细节

    1.访问父类的属性,但不能访问父类的private属性super.属性名

    2.访问父类的方法,不能访问父类的private方法super.方法名(参数列表)

    3.访问父类的构造器,super(参数列表),只能放在构造器的第一句,只能出现一句

super与this比较

image-20230819153247524

overwrite

方法覆盖(重写)就是子类有一个方法和父类的某个方法的名称返回类型参数一样,那么我们就说子类的方法覆盖了父类的方法

1. 子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类, \textcolor{blue}{子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类,} 子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类,比如父类返回类型是Obeject,子类方法返回类型是String

public Object getInfo(){}//父类
public String getInfo(){}

2. 子类方法不能缩小父类方法的访问权限 \textcolor{blue}{子类方法不能缩小父类方法的访问权限} 子类方法不能缩小父类方法的访问权限(否则会报错)

protected void say(){} //父类
public void say(){}

多态

方法和对象具有多种形态,重载和重写也体现多态

对象的多态:

    1.一个对象的编译类型运行类型可以不一致

    2.编译类型在定义对象时,就确定了,不能改变

    3.运行类型可以改变

    4. 编译类型看定义时 = 号的左边,运行类型看 = 号的右边 \textcolor{blue}{编译类型看定义时=号的左边,运行类型看=号的右边} 编译类型看定义时=号的左边,运行类型看=号的右边

Animal animal=new Dog();//animal编译类型是Animal,运行类型Dog
animal=new Cat();//animal的运行类型变成了Cat,编译类型仍然是Animal

多态的前提,是两个对象(类)存在继承关系

向上转型:

​ 父类的引用指向子类的对象

​ 语法:父类类型 引用名=new 子类类型()

​ 特点:编译类型看左边,运行类型看右边

​            可以调用父类中的所有成员(遵守访问权限)

            不能调用子类中特有成员;(编译阶段能调用哪些成员由编译类型决定)

            方法的运行效果看子类(运行类型)的具体实现(和子类的调用规则一样,先从子类找)

            属性没有重写之说!属性的值看编译类型

向下转型:

    1. 语法:子类类型 引用名=(子类类型) 父类引用

    2.只能强制父类的引用,不能强制父类的对象

​ ( new()出来,就已经规定好了,无法改变,指向它的引用可以改)

    3. 要求父类的引用必须指向的是当前目标类型的对象 \textcolor{blue}{要求父类的引用必须指向的是当前目标类型的对象} 要求父类的引用必须指向的是当前目标类型的对象

    4.可以调用子类类型中所有的成员

多态细节

public class PolyDetail {
    public static void main(String[] args) {

        //向上转型: 父类的引用指向了子类的对象
        //语法:父类类型引用名 = new 子类类型();
        Animal animal = new Cat();
        Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的父类

        //向上转型调用方法的规则如下:
        //(1)可以调用父类中的所有成员(需遵守访问权限)
        //(2)但是不能调用子类的特有的成员
        //(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
        //animal.catchMouse();错误
        //(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
        //,然后调用,规则我前面我们讲的方法调用规则一致。
        animal.eat();//猫吃鱼..
        animal.run();//跑
        animal.show();//hello,你好
        animal.sleep();//睡

        //希望可以调用Cat的 catchMouse方法
        //多态的向下转型
        //(1)语法:子类类型 引用名 =(子类类型)父类引用;
        //问一个问题? cat 的编译类型 Cat,运行类型是 Cat
        Cat cat = (Cat) animal;
        cat.catchMouse();//猫抓老鼠
        //(2)要求父类的引用必须指向的是当前目标类型的对象
        //Dog dog = (Dog) animal; //可以吗? 错误

        System.out.println("ok~~");
    }
}
public class Animal {
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void run(){
        System.out.println("跑");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void show(){
        System.out.println("hello,你好");
    }

}
class Dog extends Animal {//Dog是Animal的子类}
class Cat extends Animal {
    public void eat(){//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){//Cat特有方法
        System.out.println("猫抓老鼠");
    }
}


public class PolyDetail02 {
    public static void main(String[] args) {
        //属性没有重写之说!属性的值看编译类型
        Base base = new Sub();//向上转型
        System.out.println(base.count);// ? 看编译类型 10
        Sub sub = new Sub();
        System.out.println(sub.count);//?  20
    }
}

class Base { //父类
    int count = 10;//属性
}
class Sub extends Base {//子类
    int count = 20;//属性
}
 class PolyDetail03 {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb instanceof  BB);// true
        System.out.println(bb instanceof  AA);// true
		
        //instanceof,判断对象的运行类型是否为XX类型或其子类型
        //aa 编译类型 AA, 运行类型是BB
        //BB是AA子类
        AA aa = new BB();
        System.out.println(aa instanceof AA);//true
        System.out.println(aa instanceof BB);//true

        Object obj = new Object();
        System.out.println(obj instanceof AA);//false
        String str = "hello";
        //System.out.println(str instanceof AA);
        System.out.println(str instanceof Object);//true
    }
}

class AA {} //父类
class BB extends AA {}//子类

动态绑定机制

image-20240318131804997

public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型 A, 运行类型 B
        A a = new B();//向上转型
        System.out.println(a.sum());//30
        System.out.println(a.sum1());//20
    }
}

class A {//父类
    public int i = 10;
    
	//动态绑定机制:
    public int sum() {//父类sum()
        return getI() + 10;//20 + 10
    }

    public int sum1() {//父类sum1()
        return i + 10;//10 + 10
    }

    public int getI() {//父类getI
        return i;
    }
}

class B extends A {//子类
    public int i = 20;

//    public int sum() {
//        return i + 20;
//    }

    public int getI() {//子类getI()
        return i;
    }

//    public int sum1() {
//        return i + 10;
//    }
}

Object类

==

    1.判断基本类型,判断的是是否相等

    2.判断引用类型,判断的是地址是否相等,即判断是不是同一个对象

equals

    是Obeject类中的方法,只能判断引用类型

    默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等(Integer,String)

Person person1 = new Person("jack", 10, '男');//Person重写了equals
Person person2 = new Person("jack", 20, '男');
System.out.println(person1.equals(person2));//假

hashcode

    哈希值主要根据地址号,不能完全等同

    两个引用指向同一个对象,则哈希值是一样

toString

    默认返回:全类名(包名+类名)+@+哈希值的十六进制

    直接输出一个对象时,toString方法会被默认调用

finalize

    1.当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作

    2.什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象。就会使用垃圾 回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。

    3.垃圾回收机制的调用,是由系统来决定,也可以通过system.gc()主动触发垃圾回收机制。

public class Finalize_ {
    public static void main(String[] args) {

        Car bmw = new Car("宝马");
        //这时 car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象, 在销毁对象前,会调用该对象的finalize方法
        //,程序员就可以在 finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)
        //,如果程序员不重写 finalize,那么就会调用 Object类的 finalize, 即默认处理
        //,如果程序员重写了finalize, 就可以实现自己的逻辑
        bmw = null;
        System.gc();//主动调用垃圾回收器

        System.out.println("程序退出了....");
    }
}
class Car {
    private String name;
    //属性, 资源。。
    public Car(String name) {
        this.name = name;
    }
    //重写finalize
    @Override
    protected void finalize() throws Throwable {
        System.out.println("我们销毁 汽车" + name );
        System.out.println("释放了某些资源...");

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值