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 @ 2024-05-26 17:06  Yang0710  阅读(8)  评论(0编辑  收藏  举报