Java面向对象的三大特征!!!

封装

概念:将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问(总结:控制)

案例一:将类中属性私有化

package day7.test3;

public class Test3 {
    private String name;//将名字私有化,使用方法来控制
    private int age;
    //在本类中使用方法对私有的name进行初始化,方便控制name的初始化
    public void setName(String naem){
        if(name.length()<10){
            this.name=name;   
        }
    }
    public void setAge(int age) {
        if(age>=0&&age<150){
            this.age=age;
        }
    }
    public String getName(){
        return name;
    }
    public int getAge() {
        return age;
    }
}

package day7.test3;

public class Test3Test {
    public static void main(String[] args) {
        Test3 a=new Test3();
        a.setName("张三");
        System.out.println(a.getName());
    }
}

案例二:将某种方法私有化

java设计模式(模板,固定套路)

解决一类问题的固定方式

单例模式,在系统中执行让某个类只创建一个对象

package day7.test4;

public class Test4 {
    static Test4 test4=null;
    private Test4(){

    }
    //单一对象,只创建一个对象
    public static Test4 getTest4(){
        if(test4==null){
            test4=new Test4();
        }
        return test4;
    }
}
package day7.test4;

import OOPUnderstand.Test;

public class Test4Test {
    public static void main(String[] args) {
        Test4 a=Test4.getTest4();
        Test4 b=Test4.getTest4();
        System.out.println(a);
        System.out.println(b);
    }
}

继承

概念:Java中,继承是一种面向对象编程的特性,允许一个类(称为子类)继承另一个类(称为父类)的属性和方法。通过继承,子类可以获得父类的属性和方法,同时可以添加新的属性和方法或修改现有方法。这种关系体现了“is-a”关系,即子类是父类的一种特殊类型。

  • 子继承父,子就可以拥有父亲的功能

  • 可以将这些共性的属性和行为抽取,这样就不需要在每个类中定义同样属性和行为,只需要类与类之间建立联系即可

好处:

  • 减少代码的冗余,提高了代码的复用性,
  • 有利于功能的扩展

使用环境

  • 满足is-a关系,即什么是什么(猫是动物,狗是动物)

继承语法

通过extends关键字,可以声明另一个A

[修饰符]class 类A{
    ......
}

[修饰符]class 类B extends 类A{
    ......
}
  • 子类会继承父类所有的实例变量实例方法
  • 子类不能直接访问父类中私有的(private)的成员变量方法
  • 在Java中,继承的关键字用的是"extends",表示子类是对父类的扩展
  • Java支持多层继承(继承体系)
  • 一个父类可以拥有多个子类
  • Java只支持单继承,不支持多重继承

Java中如果一个类没有使用extends关键字显示的继承其他类,那么这个类默认继承Object类

1689492299941

所以Java中所有的类都直接或间接的继承了Object类

注:父类不可以使用子类功能

方法的重写

当父类中的方法功能实现不能满足子类需求时,可以对方法进行重写(Override)

子类可以对从父类中继承的方法来进行改造,在程序执行时,子类方法将覆盖父类方法,我么称为 方法的重写 也称方法的覆盖

注:构造方法,静态方法不能重写,成员变量不存在重写

方法重写的规则

  1. 方法名必须和父类相同,参数列表相同(否则调用的是父类方法)

  2. 方法返回值类型与父类保持一致

    即子类重写方法结构与父类一致

  3. 子类方法使用的访问权限不能小于父类被重写的访问权限

    注意:1.父类私有方法不能重写 2.跨包的父类默认权限的方法也不能重写

  4. 子类方法抛出的异常不能大于父类被重写方法的异常

@Override使用说明

@Override是java中定义的注解标签,用来进行标记(进阶部分细讲)写在方法上面,表示此方法是从父类重写而来,用来检测是不是满足重写方法的要求
这个注解就算不写,只要格式满足要求,也是正确的方法覆盖重写。建议保留,这样编译器可以帮助我们检查格式,另外也可以让阅读源代码的程序员清晰的知道这是一个重写的方法

帮助进行语法检测

  • 例如
//父类
public  class Cuiweiyang {
    String name;
    String sex;
    //public static abstract void setName(String name);不能使用static调用
    public void eat() {
        
    }

    public void setName(String name) {
        
    }

    public void abst() {
        
    }

    public void sleep(){
        System.out.println("父亲睡觉");
    }
}
//子类
public class Dengqinwen extends Cuiweiyang {
    public void eat(){
        System.out.println("吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("儿子睡觉");
    }

    @Override
    public void setName(String name) {

    }
    @Override
    public void abst() {

    }

    public Dengqinwen(){

    }
}

super关键字

java类中使用super来调用父类中的操作

  • 用于访问父类中定义的属性

  • 调用父类中定义的成员方法

  • 用于在子类构造器中调用父类构造器

  • @Override
        public void setName(String name) {
            super.setName("123");
        }
    

注意

  • 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员
  • super的追溯不仅限于直接父类还可以是父类的父类
  • superthis的用法相像,this代表本类对象的引用super代表父类的内存空间识的标

误区:不要把super误认为识父类对象,在创建子类对象时,不会创建父类对象,只会将父类中的信息加载到子类对象中存储

继承中的构造方法

  • 子类继承父类时,不会继承父类的构造方法。只能通过“super(形参列表)”的方式调用父类指定的构造方法。
  • 规定super(形参列表),必须声明在构造器的首行
  • 如果在子类构造器的首行没有显示调用super(形参列表),则子类此构器
    默认调用super(),即调用父类中空参的构造器。
  • 这么做是为了保证先对父类成员进行初始化

开发中常见错误

  • 如果子类构造器中既未显示调用父类或本类的构造器,且父类中又没有空参构造器,则编译错误
父类
package day7.extend;

public class Animal {
    private String name;
    private int age;
    public Animal(){
        System.out.println("父类无参初始化");
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;//this指当前对象
    }

    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 void eat(){
        System.out.println("eat thing");
    }
}

 子类1
package day7.extend;


public class Cat extends Animal {
    public Cat(){
        //super();
        System.out.println("子类无参初始化");
    }

    public Cat(String name, int age) {
        super(name, age);
        System.out.println("有参构造");
    }

    @Override
    public void eat(){
        System.out.println("eat cat's food");
    }

}
class TestAnimal {
    public static void main(String[] args) {
        Cat mm = new Cat();
        System.out.println("年龄" + mm.getAge());
        System.out.println("名字" + mm.getName());
        mm.eat();
    }
}

运行结果:

1689500705786

无参构造有无super()结果都是一样的,不过推荐写上super()

package day7.extend;


public class Cat extends Animal {

    public Cat(){
        super();
        System.out.println("子类无参初始化");
    }

    public Cat(String name, int age) {
        //super(name, age);
        System.out.println("有参构造");
    }

    @Override
    public void eat(){
        System.out.println("eat cat's food");
    }

}
class TestAnimal {
    public static void main(String[] args) {
        Cat mm = new Cat("咪咪",2);
        System.out.println("年龄" + mm.getAge());
        System.out.println("名字" + mm.getName());
        mm.eat();
    }
}

1689504634339

注释掉super(name,age),后发现虽然调用子类中有参构造,但运行结果依然是未初始化的成员变量

package day7.extend;


public class Cat extends Animal {

    /**
     * chidongxi
     */

    public Cat(){
        super();
        System.out.println("子类无参初始化");
    }

    public Cat(String name, int age) {
        super(name, age);
        System.out.println("有参构造");
    }

    @Override
    public void eat(){
        System.out.println("eat cat's food");
    }

}
class TestAnimal {
    public static void main(String[] args) {
        Cat mm = new Cat("咪咪",2);
        System.out.println("年龄" + mm.getAge());
        System.out.println("名字" + mm.getName());
        mm.eat();
    }
}

1689504754560

取消掉注释后,加上super(name,age),就可以调用父类的有参构造方法对成员变量进行了初始化

注意,不能把子类构造方法中默认会调用父类无参构造方法,如果需要显示的使用super调用,必须放在构造方法的第一行,还可以调用父类中指定的构造方法

1689505060654

抽象类

一个类中没有足够的信息来描绘一个具体的对象,这样的类就是抽象类

被abstract类关键字修饰的类,可能会出现抽象方法

注:抽象类除了不能实例化对象外,类的其他功能依然存在,成员变量,成员方法和构造方法,且没有抽象变量这一说法

特点:

  1. 抽象类不能被实例化(不能创建对象),但可以有构造方法,因为抽象类中含有无具体实现的方法所以不能用抽象类创建对象
  2. 抽象类只能用做基类,表示的是一种关系,继承抽象类非抽象类必须实现其中的所有抽象方法,而已实现方法的参数,返回值要和抽象类中的方法一样,否则,该类也必须声明为抽象类
[访问权限符] abstract class 类名{

}
public abstract class Abstract{
	
}

抽象方法

抽象方法是一种特殊的方法:它只有声明,而没有具体的实现.

[权限修饰符] abstract [返回值类型] 方法名 (参数列表);
public abstract void setName(String name);

抽象方法必须用abstract关键字进行修饰

注:不可以抽象构造方法

抽象方法是为了子类对其的重写,所有不能使用static修饰..被static修饰的为静态方法是可以通过类名直接调用的,但是抽象方法没有任何具体的实现,所以是错误的(静态的方法是不可以被重写的)

多态

多种状态

父类的引用指向子类对象,从而产生多种形态

Animal dog = new Dog();//这里Dog是Animal子类
Animal cat = new Cat();

同一种事物,在不同时刻表现不同状态

二者之间存在直接或间接的继承关系时,父类引用指向子类的对象,即形成多态

  • 在编译期类型是父类,运行期类型是子类时,被称为父类引用指向子类对象
class Animal{
....
}
class Cat extends Animal{
.....
}
class Dog extends Animal{

}
Animal cat=new Cat();
Animal dog=new Dog();//Animal的引用指向Dog的对象

向上转型

package homeworkday7.chouxiang;

public abstract class Cuiweiyang {
    String name;
    String sex;
//public static abstract void setName(String name);不能使用static调用
    public abstract void eat();
    public abstract void setName(String name);
    public abstract void abst();
}
package homeworkday7.chouxiang;

public class Dengqinwen2 extends Cuiweiyang {

    public void eat(){
        System.out.println("喝水");
    }

    @Override
    public void setName(String name) {

    }

    @Override
    public void abst() {

    }
}
package homeworkday7.chouxiang;

public class Test {
    public static void main(String[] args) {
        Cuiweiyang dqw=new Dengqinwen();
        Cuiweiyang dqw2=new Dengqinwen2();
        dqw.eat();//编译期间调用的是父类eat,运行期间运行的是子类eat方法
       
    }
}

1689575220912

编译期间是看父类,运行期间切记是在运行子类方法,就算子类无,父类有,也是运行子类所继承的方法,绝对不是运行父类方法

多态的好处:提高代码的扩展性

class Animal{
	public void eat(){}
    ....
}
class Cat extends Animal{
	public void eat(){
        System.out.println("猫吃鱼");
    }
    .....
}
class Dog extends Animal{
	public void eat(){
    	System.out.println("狗吃骨头");
    }
        .....
}
class Test{
    public static void main(String[]args){
      Animal cat=new Cat();
	  Animal dog=new Dog();//Animal的引用指向Dog的对象  
    }
}

class Person{
    public void Feed(Animal animal){
        animal.eat;//此时传递的参数是子类对象的地址
    }
    //避免了下面的繁琐,提高代码扩展性
    public void Feed(Dog dog){
        dog.eat;
    }
    public void Feed(Cat cat){
        cat.eat;
    }
}

多态环境下对成员方法(非静态)的调用

如上,
cat.eat();
//调用的是子类中的方法

简单来说就是:编译看左边,运行看右边

多态环境下对静态成员方法的调用

package homeworkday7.chouxiang2;
class Animal {
    public static void eat(){
        System.out.println("吃食物");
    }
}
class Cat extends Animal{
    public static void eat(){
        System.out.println("猫吃鱼");
    }
}
class Test{
    public static void main(String[] args) {
        Animal cat=new Cat();
        cat.eat();//调用的是Animal的方法
    }
}

1689566001921

简单的说:编译运行都看左边

注意:变量不存在被子类覆盖写这一说法,只有方法存在覆写

为了实现多态性,我们将子类类型向上转为了父类类型.但是一旦类型上升为父类类型,那么就调用不到子类特有的方法

解决办法:

就行向下转型,把父类转换为子类类型

向下转型(强制类型转换)

格式 [类型]对象名1 = (类型)对象名2

将后面大的父类对象转换为子类小的对象

注:同父类的子类不能相互转化

package homeworkday7.chouxiang;

public class Test {
    public static void main(String[] args) {
        Cuiweiyang dqw=new Dengqinwen();
        Cuiweiyang dqw2=new Dengqinwen2();
        Person zs = new Person();
          dqw.sleep();
          dqw2.sleep();
          Dengqinwen dqw3=(Dengqinwen) dqw;//把Cuiweiyang类型强制转化为子类的Dengqinwen类型
          zs.feed(dqw3);
    }
}

Dengqinwen2 dqw4=(Dengqinwen2) dqw3;//错误,同父类的子类不能相互转化

屏幕截图 2023-07-17 154410

优缺点

优点

  1. 灵活性:多态使用使代码更加灵活,可以通过父类类型的引用变量来引用不同子类对象,从而实现不同对象的统一操作
  2. 可扩展性:通过多态,我们可以方便地扩展和添新的子类,而不需要修改已有的代码
  3. 代码重用:多态可以提高代码的重用性,通过定义父类类型的方法,可以在不同的子类中进行具体实现,减少了代码的冗余

缺点

  1. 性能损失:多态需要在运行时进行动态绑定和方法调用,这会带来一定的性能损失,相比于直接调用子类方法,多台调用会稍微慢一些
  2. 可读性降低:由于多态的特性,代码的行为可能会依赖于运行时的实际对象类型,这可能会增加代码的复杂性和难以理解程度
  3. 限制:多态只能通过父类类型的引用变量来引用子类对象,而不能直接访问子类特有的方法和属性,如果需要访问子类特有的功能,需要进行类型转换
posted @   Yang0710  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
  1. 1 イエスタデイ(翻自 Official髭男dism) 茶泡饭,春茶,kobasolo
  2. 2 世间美好与你环环相扣 柏松
世间美好与你环环相扣 - 柏松
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 尹初七

作曲 : 柏松

编曲 : 彭圣杰

偏偏秉烛夜游

偏偏秉烛夜游

午夜星辰 似奔走之友

爱你每个结痂伤口

酿成的陈年烈酒

入喉尚算可口

入喉尚算可口

怎么泪水 还偶尔失守

邀你细看心中缺口

裂缝中留存 温柔

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

让樱花偷偷 吻你额头

让世间美好 与你环环相扣

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

当樱花开的纷纷扬扬

当世间美好 与你环环相扣

特别鸣谢:槿葵,我们的海报制作妹妹。

原唱:柏松

吉他:柏松

和声:柏松

录音:柏松

混音:张强

点击右上角即可分享
微信分享提示