首页 > 其他分享 >面向对象

面向对象

时间:2024-05-19 17:18:42浏览次数:26  
标签:System class 面向对象 println 父类 public out

面向对象

1 继承

1.1 继承概述

面向对象的三大特征之一:封装、继承、多态

如果一些类中的属性和方法是重复的,可以将这些重复的属性和代码提取到一个新的类中,利用extends关键字让原来的类和新的类产生联系。这种联系称之为继承。提取出来的新的类是父类(超类/基类),原来的类是子类(派生类)。子类通过继承父类可以使用父类中的一部分的方法和属性。

注意:子类通过继承可以继承父类全部的属性和方法,但是只有一部分属性和方法对子类可见。

继承的好处:提高代码的复用率

注意:Java是单继承的。有多层继承,但是没有多继承。

单继承和多继承的比较:多继承在代码的复用性上要优于单继承,但是在调用方法的时候会产生混淆。

Java中的顶级父类是Object

1.2 权限修饰符

权限修饰符就是来限定成员的使用的范围。

本类中 子类中 同包类中 其他类中
public 可以 可以 可以 可以
protected 可以 可以 可以 不可以
default 可以 同包子类可以 可以 不可以
private 可以 不可以 不可以 不可以

1.3 super

super可以在子类中调用父类的方法和属性

super()     访问父类对象的构造方法 必须在方法体中的有效代码第一行
super.成员方法()   访问父类对象的方法
super.成员变量  访问父类对象的成员变量
public Dog(){
        // 调用父类的无参构造方法
        super();
        System.out.println("dog构造方法被执行了");
    }

    public void dogEat(){
        // 调用父类对象的eat方法  super相当于父类对象
        super.eat();
        System.out.println("小狗啃骨头");
        super.name = "";
    }

在构造方法中默认会调用父类的无参构造,如果父类没有无参构造,就会编译不通过。父类可以提供无参构造,或者手动调用父类的有参构造。

public Dog(){
        // 如果没有写super(参数),系统会默认提供一个super(),调用父类的无参构造,如果父类没有无参构造,编译不通过
        super("佩奇");
        // 调用父类的无参构造方法 必须在方法体中的有效代码第一行
        System.out.println("dog构造方法被执行了");
    }

super()是调用父类对象的构造方法,this()是调用当前对象的构造方法,它们都要求在方法体的有效代码第一行。所有不能共存。

public Dog(){
        // 如果没有写super(参数),系统会默认提供一个super(),调用父类的无参构造,如果父类没有无参构造,编译不通过
        super("佩奇");
        // 调用父类的无参构造方法 必须在方法体中的有效代码第一行
        System.out.println("dog构造方法被执行了");
    }

    public Dog(String age){
        this();
    }

1.4 重写

  • 概述

在父子类中存在方法签名(方法的名字和参数列表类型)相同的非静态方法,称之为方法的重写,也称之为覆盖。

调用时执行的是子类的方法。

  • 方法的重写遵循五个原则

    • 方法签名一致
    • 如果父类中的方法的返回值类型是基本数据类型和void,那么子类在重写方法的时候返回值类型必须要保持一致。
    • 子类重写的方法的权限修饰符的范围要大于等于父类对应方法的权限修饰符范围
    public class Proffession {
    
        protected void work(){
            System.out.println("在工作中...");
        }
    
    
    }
    
    
    class Doctor extends Proffession{
        // 方法的重写/覆盖
        public void work(){
            System.out.println("医生在治病救人");
        }
    }
    
    • 如果父类方法的返回值类型是引用数据类型,那么子类重写的方法的返回值类型要么与父类方法返回值类型一致,要么是其子类(返回值类型可以是父类,也可以是其子类)
class A{}
class B extends A{}

class C{
    public A m(){
        return null;
    }
}


class D extends C{
    public B m(){
        return null;
    }
}
  • 以后讲异常时再说

2 多态

多态是继封装、继承之后,面向对象的第三大特性。

Java作为面向对象的语言,可以描述一个事物的多种形态。比如Student类继承Person类,一个Student对象既是Student,也是Person.

多态的体现形式:

​ 编译时多态:方法的重载

​ 运行时多态:方法的重写、向上转型

向上转型的使用

public class Pet {


    String name;

    public void eat(){
        System.out.println("mixi");
    }
}
public class Cat extends Pet {

    String color;

    public void miao(){
        System.out.println("一起学猫叫~");
    }


    public void eat() {
        System.out.println("猫吃小鱼");
    }
}
public static void main(String[] args) {
        // 向上转型   父类  对象名 = new 子类();

        /**
         * 用父类来声明对象,用子类来创建对象
         * 在使用向上造型创建对象的时候
         * 编译期间只会检查声明类和创建类之间是否有继承关系
         * 而并不关心具体是哪一个子类
         * 到了运行的时候才会确定具体的子类
         * 编译期不确定子类,所以只能按照父类的规定来编译
         * 等到运行期间确定子类,使用子类的对象来运行
         *
         * 编译看左边,运行看右边
         */
        //多态,运行时的多态
        Pet pet = new Cat();
        pet.eat();
//        ClassCastException 类型不匹配异常
        Dog cat = (Dog) pet;
    }

    public static void test(Pet pet){
        Cat cat = (Cat) pet;
        cat.color = "红色";
        System.out.println(cat.color);
    }

如果左边类型是右边类型的子类,那么可以进行强转。这样就可以使用子类中的属性和方法

public static void test(Pet pet){
    // 子类  =  (子类)父类;
        Cat cat = (Cat) pet;
        cat.color = "红色";
        System.out.println(cat.color);
    }

思考:

  • 为什么子类重写的方法的权限修饰符的范围要大于等于父类对应方法的权限修饰符范围?
public static void main(String[] args) {
        /**
         * a的对象的声明类是A类,所以a对象能够干什么看的是A类,A类
         * 告诉a对象有一个m方法可以使用,而且m方法可以在任何地方使用
         */
        A a = new B();
        /**
         * a对象本质上是B类产生的对象,所以m方法执行时候要看B类,B类的m方法不能在任何地方使用 --产生了冲突
         */
        a.m();
    }

class A{
    public void m(){}
}

class B extends A{

    public void m() {

    }
}
  • 为什么 父类方法的返回值类型是引用数据类型,那么子类重写的方法的返回值类型要么与父类方法返回值类型一致,要么子类方法的返回值类型是父类方法返回值类型的子类?

![image-20240519154402385](/Users/zewei/Library/Application Support/typora-user-images/image-20240519154402385.png)

3 static关键字

static是一个修饰符,可以修饰变量、方法、代码块、内部类

3.1 静态变量

static修饰的变量称之为静态变量。静态变量是随着类的加载而加载到方法区的,在方法区中被赋予了默认值。静态变量是先于对象而出现的。静态变量是属于类的,而不是属于对象的,是被多个对象共享的。该类产生的所有的对象都是使用同一个静态变量,每一个对象存储的都是静态变量的地址。

静态变量也称之为类变量,可以通过类名来调用。

使用静态变量的格式

类名.静态变量  推荐
对象名.静态变量  不推荐
public class Person {
    // 成员变量
    // 姓名
    String name;
    // 年龄
    int age;
    // 功夫  -- 静态变量
    static String kongfu;

    public String toStr(){
        return name + "\t" + age + "\t" + kongfu;
    }
}
    public static void main(String[] args) {
        // 使用静态变量
        Person.kongfu = "葵花宝典";
    }

![image-20240519160502098](/Users/zewei/Library/Application Support/typora-user-images/image-20240519160502098.png)

注意点:

  • 类是加载到方法区的
  • 类是在第一次被使用的时候才会放到方法区中
  • 类只加载一次

思考:

  • 静态变量能否定义到构造方法中?

不能.静态变量在类加载时加载到方法区并且初始化,构造方法在创建对象时执行。静态变量存储在方法区,构造方法在栈内存中执行,对应创建出来的对象在堆内存。

静态变量能否定义在成员方法中?

不能

3.2 静态方法

static修饰的方法称之为静态方法。静态方法在类加载的时候加载到方法区,并没有执行而是存储在方法区。在方法被调用的时候到栈内存中执行。静态方法本身也是先于对象存在的,所以习惯上是通过类名来调用静态方法。静态方法一般用于后面使用的工具类中。

格式:

类名.静态方法();

思考:

  • 静态方法能够使用this/super?

不可以。this代表当前对象,super代表父类对象,都是晚于静态方法出现的。当使用类名.静态方法时,对象还没有出现。

  • 静态方法中能否直接使用本来中的非静态方法?

不可以,因为非静态方法需要对象调用. e

eg:

eat()相当于 this.eat();

  • 静态可以被继承吗?

可以

public class StaticDemo {
    public static void main(String[] args) {
        B.m();
    }
}

class A{
    public static void m(){
        System.out.println("A m...");
    }
}

class B extends A{

}
  • 静态方法可以被重写吗?

不可以.

父子类中可以存在方法签名一致的静态方法,这种情况称之为隐藏(hide)

隐藏也适用于重写的五个原则。

public class StaticDemo {
    public static void main(String[] args) {
        // 向上转型
        A a = new B();
        a.m();
    }
}

class A{
    public static   void m(){
        System.out.println("A m...");
    }
}

class B extends A{

    public static void m(){
        System.out.println("B m...");
    }
}

课堂练习:统计一个类所创建的对象的个数

public class A {
    static int i = 0;
    // 构造代码块  在每一次创建对象时都会先于构造方法执行
    {
        i++;
    }
}

3.3 静态代码块

用static修饰的{}就称之为静态代码块,在类中方法外定义。这个代码块只会在类加载的时候执行一次

经常在静态代码块中做一些数据的初始化操作。静态代码块在方法区中执行。

public class B {
    // 静态代码块 在类加载到方法区时执行  因为类只加载一次,所以静态代码块只会执行一次
    static {
        System.out.println("静态代码块执行了");
    }
}

静态代码块执行顺序先于构造代码块,构造代码块(在创建对象前执行)的执行顺序先于构造方法

3.4 执行顺序问题

public class TestDemo {
    public static void main(String[] args) {
        new SA();
    }
}


class SA{
    static {
        System.out.println("A1");
    }

    {
        System.out.println("A2");
    }
    
    public SA(){
        System.out.println("A3");
    }
}

顺序是A1 A2 A3

public class TestDemo {
    public static void main(String[] args) {
        new SA();
        new SA();// A1 A2 A3 A2 A3
    }
}

顺序是A1 A2 A3 A2 A3

    public static void main(String[] args) {
        // 先加载父类,然后加载子类
        // 调用父类构造方法,再去创建子类对象
        new SB();// A1 B1 A2 A3 B2 B3
    }
}


class SA{
    static {
        System.out.println("A1");
    }

    {
        System.out.println("A2");
    }

    public SA(){
        System.out.println("A3");
    }
}

class SB extends SA{
    static {
        System.out.println("B1");
    }

    {
        System.out.println("B2");
    }

    public SB(){
        System.out.println("B3");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        // 先加载父类,然后加载子类
        // 调用父类构造方法,再去创建子类对象
        new SB();// A1 C B1 A2 A3 B2 B3
    }
}


class SA{
    static {
        System.out.println("A1");
    }

    {
        System.out.println("A2");
    }

    public SA(){
        System.out.println("A3");
    }
}

class SB extends SA{
    static SC c = new SC();
    static {
        System.out.println("B1");
    }

    {
        System.out.println("B2");
    }

    public SB(){
        System.out.println("B3");
    }
}

class SC{
    public SC(){
        System.out.println("C");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        // 先加载父类,然后加载子类
        // 调用父类构造方法,再去创建子类对象
        // 这个情况SD d只是声明,根本没有创建对象,d的默认值就是null
        new SB();// A1 C B1 A2 A3 B2 B3
    }
}


class SA{
    SD d;
    static {
        System.out.println("A1");
    }

    {
        System.out.println("A2");
    }

    public SA(){
        System.out.println("A3");
    }
}

class SB extends SA{
    static SC c = new SC();
    static {
        System.out.println("B1");
    }

    {
        System.out.println("B2");
    }

    public SB(){
        System.out.println("B3");
    }
}

class SC{
    public SC(){
        System.out.println("C");
    }
}

class SD extends SC{
    public SD(){
        System.out.println("D");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        // 先加载父类,然后加载子类
        // 调用父类构造方法,再去创建子类对象
        new SB();// A1 C B1 A2 C D A3 B2 B3
    }
}


class SA{
    SD d;
    static {
        System.out.println("A1");
    }

    {
        System.out.println("A2");
        d = new SD();
    }

    public SA(){
        System.out.println("A3");
    }
}

class SB extends SA{
    static SC c = new SC();
    static {
        System.out.println("B1");
    }

    {
        System.out.println("B2");
    }

    public SB(){
        System.out.println("B3");
    }
}

class SC{
    public SC(){
        System.out.println("C");
    }
}

class SD extends SC{
    public SD(){
        System.out.println("D");
    }
}

总结:执行顺序 父类静态 -->子类静态 -->父类非静态 (构造代码块和构造方法)-->子类非静态(构造代码块和构造方法)

标签:System,class,面向对象,println,父类,public,out
From: https://www.cnblogs.com/460759461-zeze/p/18200507

相关文章

  • python 面向对象(进阶篇)
    python面向对象(进阶篇) 上一篇《Python面向对象(初级篇)》文章介绍了面向对象基本知识:面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用类是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中)对象,根据模板创建的实例(即......
  • python教程12-面向对象进阶
    1、classmethod类方法类方法只能访问类变量,不能访问实例变量2、staticmethod静态方法不能访问类变量,也不能访问实例变量。除非在实例调用时给方法传实例。3、反射1-判断对象是否有属性的情况用法: 实例: __name__,模块被其他模块导入的时候调用,是你叫的名字。模块自己主......
  • python教程11-面向对象
    python的面向对象和java有一些不一样:(java中,只有在类中定义的变量实例才能用,但是python更加灵活)类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实......
  • 21.面向对象【五】
    【一】内置方法补充1)__call__#__call__:当类()或对象()调用时触发classEg:def__init__(self):print('执行__init__')def__call__(self,*args,**kwargs):print('执行__call__')obj=Eg()#执行__init__obj()#执行__call__#校验当......
  • 面向对象编程(basic)
    面向对象内容的三条主线:Java类及类的成员:(重点)属性、方法、构造器;(熟悉)代码块、内部类面向对象的特征:封装、继承、多态、(抽象)其他关键字的使用:this、super、package、import、static、final、interface、abstract等1.面向对象VS面向过程面向过程思想线性思维步......
  • Python进阶之面向对象编程
    【一】人狗大战小游戏【1】游戏前提分析人可以打狗,狗掉血,狗可以咬人,人掉血人的属性有名字、年龄、伤害、血量、类型狗的属性有名字、年龄、伤害、血量、类型【2】游戏实现(1)定义人和狗的属性#【1】用字典定义,代码较冗余dog1={'name':'狗蛋','d_type':'中......
  • 面向对象、面向过程、类与对象
    【一】人狗大战【1】人狗大战小游戏描述人可以打狗,狗掉血,狗可以咬人,人掉血【2】人狗大战小游戏实现(0)分析人的属性人的名字人的类型人的年龄人的攻击力人的生命值狗的属性狗的名字狗的类型狗的攻击值狗的生命值(1)定义人和狗的参数方式一:使用字典定义属......
  • 面向对象的三大特性、封装的介绍及属性、装饰器property、员工管理系统
    【一】面向对象的三大特性封装:封装指的就是把数据与功能都整合到一起继承多态【二】什么是封装封装是对具体对象的一种抽象意思就是将某部分功能和代码隐藏起来,在程序外边看不到,只能在程序内部使用【三】为什么要封装?封装数据的主要原因是:保护隐私(把不想别人......
  • 20.面向对象【四】
    【一】抽象类抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化#所有继承父类的子类必须重写父类的某些方法,这个父类就叫抽象类importabcclassAnimal(metaclass=abc.ABCMeta):def__init__(self,color,foot):self.color=colorself.f......
  • Java面向对象04——三大特性之多态
    多态1、什么是多态在Java中,多态是面向对象编程中的一个重要概念,它允许不同类型的对象对同一方法进行不同的实现。具体来说,多态性指的是通过父类的引用变量来引用子类的对象,从而实现对不同对象的统一操作。2、多态实现的条件在Java中,要实现多态性,就必须满足以下条件:继承关......