day08_面向对象高阶(1)

本文详细解析了Java中static关键字的使用,包括静态成员变量和方法的区别、内存原理,以及如何应用在工具类和继承关系中。此外,还讨论了继承、多态、final关键字的概念及其在类、方法和变量中的作用。
摘要由CSDN通过智能技术生成

1.static关键字_静态的

1.1static修饰成员变量

Java中的成员变量按照有无static修饰分为两种:类变量、实例变量。它们的区别如下图所示:

区别:

有static修饰的变量属于类,在内存中只有一份,用类名调用

没有static修饰的变量属于对象,每一个对象都有一份,用对象调用

1.2static修饰成员方法

区别:

有static修饰的方法属于类,在内存中只有一份,用类名调用

没有static修饰的方法属于对象,每一个对象都有一份,用对象调用

代码案例:

//定义一个Student类,在类中定义一个类方法、定义一个实例方法
public class Student{
    double score;
    
    //类方法:
    public static void printHelloWorld{
        System.out.println("Hello World!");
        System.out.println("Hello World!");
    }
    
    //实例方法(对象的方法)
    public void printPass(){
        //打印成绩是否合格
        System.out.println(score>=60?"成绩合格":"成绩不合格");
    }
}

代码测试:

//在定义一个测试类,注意类方法、对象方法调用的区别
public class Test2{
    public static void main(String[] args){
        //1.调用Student类中的类方法
        Student.printHelloWorld();
        
        //2.调用Student类中的实例方法
        Student s = new Student();        
        s.printPass();
        
        //使用对象也能调用类方法(不建议)
        s.printHelloWorld();
    }
}

1.3static修饰成员方法的内存原理

1.类方法:

static修饰的方法,可以被类名调用,是因为它是随着类的加载而加载的;所以类名直接就可以找到static修饰的方法

2.实例方法:

非static修饰的方法,需要创建对象后才能调用,是因为实例方法中可能会访问实例变量,而实例变量需要创建对象后才存在。所以实例方法,必须创建对象后才能调用。

1.4静态方法的应用_定义工具类

如果一个类中的方法全都是静态的,那么这个类中的方法就全都可以被类名直接调用,由于调用起来非常方便,我们把这样的类就叫做工具类。

代码示例:

public class MyUtils{
    public static String createCode(int n){
        //1.定义一个字符串,用来记录产生的验证码
        String code = "";
        
        //2.验证码是由所有的大写字母、小写字母或者数字字符组成
        //这里先把所有的字符写成一个字符串,一会从字符串中随机找字符
        String data = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ";
        
        //3.循环n次,产生n个索引,再通过索引获取字符
        Random r = new Random();
        for(int i=0; i<n; i++){
            int index = r.nextInt(data.length());
            char ch = data.charAt(index);
            //4.把获取到的字符,拼接到code验证码字符串上。
            code+=ch;
        }
        
        //最后返回code,code的值就是验证码
        return code;
    }
}

调用方法

public class LoginDemo{
    public static void main(String[] args){
    //类名直接调用方法
        System.out.println(MyUtils.createCode());
    }
}

1.5静态代码块和代码块

public class Student {
    static int number = 80;
    static String schoolName = "doit";
    // 静态代码块
    static {
        System.out.println("静态代码块被执行了~~");
        schoolName = "多易多易";
    }
    
    {
     System.out.println("代码块被执行了~~");
     schoolName = "多易多易1";
    }
}

调用测试

public class Test {
    public static void main(String[] args) {
        //调用瞅瞅
        System.out.println(Student.number);
        System.out.println(Student.number);
        System.out.println(Student.number);

        System.out.println(Student.schoolName); // 
    }
}

static的注意事项

静态方法可以直接访问静态的成员变量,但是不能访问非静态的成员变量

非静态方法中,非静态成员变量和静态的都可以访问

静态的方法,不能使用this关键字,但是非静态的方法可以

关于静态代码块重点注意:

静态代码块,随着类的加载而执行,而且只执行一次。

代码块创建一次对象就会执行一次,在静态代码块之后执行

2.继承

2.1什么是继承?

你爹的就是你的,这就是继承,不过你爹的钱,摆在明面上的东西你是能继承过来的,但是你爹的小情人,这是私有的,可不能给你。 阴险一下,哈哈

继承的特点:

子类能继承父类的非私有成员变量和成员方法

继承后的对象创建:

子类的对象由父类和子类共同完成的

代码示例:

//定义一个父类
public class A{
    //公开的成员
    public int i;
    public void print1(){
        System.out.println("===print1===");
    }
    
    //私有的成员
    private int j;
    private void print2(){
        System.out.println("===print2===");
    }
}

//写一个B类,继承A类
//此时B类就拥有了A类(父类)里面所有非私有的成员变量和方法
public class B extends A{
    public void print3(){
        //由于i和print1是属于父类A的公有成员,在子类中可以直接被使用
        System.out.println(i); //正确
        print1(); //正确
        
        //由于j和print2是属于父类A的私有成员,在子类中不可以被使用
        System.out.println(j); //错误
        print2();
    }
}

测试类:

public class Test{
    public static void main(String[] args){
        B b = new B();
        //父类公有成员,子类对象是可以调用的
        System.out.println(i); //正确
        b.print1();
        
        //父类私有成员,子类对象时不可以调用的
        System.out.println(j); //错误
        b.print2(); //错误
    }
}

2.2继承的内存原理

子类对象实际上是由子、父类两张设计图共同创建出来的。所以,在子类对象的空间中,既有本类的成员,也有父类的成员。但是子类只能调用父类公有的成员。

2.3为什么要有继承

说白了,可以提高代码的复用性

观察下面的代码,看看有什么可以优化的地方??

思考:

可以发现:

两个类的很多代码都是一样的,比如name,salary,gender这三个属性是一样的

然后get方法和set方法也是一样的

如果把他们相同的抽取出来一个父类,父类里面写这些属性方法,子类中直接继承过来是不是只要写一份呢?

再看下面的代码:

//定义一个父类
public class Doit {
    private String name ;
    private double salary;
    private String gender;

    public String getName() {
        return name;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

//定义老师的类继承Doit父类

public class Teacher1 extends Doit{
    private String course;

    public String getCourse() {
        return course;
    }

    public void setCourse(String course) {
        this.course = course;
    }

}


//定义班主任类继承Doit父类
public class BanZhuRen1 extends Doit{
    private int studentNum;

    public int getStudentNum() {
        return studentNum;
    }

    public void setStudentNum(int studentNum) {
        this.studentNum = studentNum;
    }


}

定义测试类

public class Test {
    public static void main(String[] args) {
        Teacher1 teacher1 = new Teacher1();
        teacher1.setCourse("java继承");
        teacher1.setName("小江");
        teacher1.setSalary(9999.99);
        teacher1.setGender("male");

        BanZhuRen1 banZhuRen1 = new BanZhuRen1();
        banZhuRen1.setStudentNum(20);
        banZhuRen1.setName("小江");
        banZhuRen1.setSalary(9999.99);
        banZhuRen1.setGender("male");
    }
}

2.4继承之后成员变量,方法,构造器的特点

思考一下:如果说父类中有一个name成员变量,会被子类继承过来,但是子类中也有一个成员变量叫name,那不就冲突了吗?这种问题怎么解决呢?

成员变量以近的为准,方法以是否重写了为准

案例:

public class Fu {
    String name = "父亲大人";
    int age = 18;

    public void print(){
        System.out.println("父亲大人的方法");
    }

}


class Zi extends Fu{
    String name = "小兔崽子";

    public void showName(){
        System.out.println(name);
    }

    @Override
    public void print(){
        System.out.println("小兔崽子的方法");
    }
}


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

        Zi zi = new Zi();
        System.out.println(zi.name);//小兔崽子

        System.out.println(zi.age);//18

        zi.print();//小兔崽子的方法

        zi.showName();//小兔崽子

    }
}

2.4.1什么是方法的重写

当子类觉得父类方法不好用,或者无法满足父类需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。

示例:

public class A {
    public void print1(){
        System.out.println("111");
    }

    public void print2(int a, int b){
        System.out.println("111111");
    }
}


public class B extends A{
    // 方法重写
    @Override // 安全,可读性好
    public void print1(){
        System.out.println("666");
    }


    // 方法重写
    @Override
    public void print2(int a, int b){
        System.out.println("666666");
    }
}



//测试类
public class Test {
    public static void main(String[] args) {
        // 目标:认识方法重写,掌握方法重写的常见应用场景。
        B b =  new B();
        b.print1();// 666
        b.print2(2, 3);//666666
    }
}

注意事项:

  1. 重写的方法上面,可以加一个注解@Override,用于标注这个方法是复写的父类方法

  2. 重写的方法返回值类型,必须与被重写的方法返回值类型一样,或者范围更小

  3. 私有方法、静态方法不能被重写,如果重写会报错。

2.5构造器的特点

其实子类的构造器中第一行默认是调用的父类构造器,所以调用的顺序如下图

访问本类成员:

this.成员变量 //访问本类成员变量

this.成员方法 //调用本类成员方法

this() //调用本类空参数构造器

this(参数) //调用本类有参数构造器

访问父类成员:

super.成员变量 //访问父类成员变量

super.成员方法 //调用父类成员方法

super() //调用父类空参数构造器

super(参数) //调用父类有参数构造器

注意:this和super访问构造方法,只能用到构造方法的第一句,否则会报错。

2.6权限修饰符

修饰符在本类中在同一个包下的其他类中在任意包下的子类中在任意包下的其他类中
private
默认
protected
public

代码示例:

测试在本类中:

public class Fu {
    // 1、私有:只能在本类中访问
    private void privateMethod(){
        System.out.println("==private==");
    }

    // 2、缺省:本类,同一个包下的类
    void method(){
        System.out.println("==缺省==");
    }

    // 3、protected: 本类,同一个包下的类,任意包下的子类
    protected void protectedMethod(){
        System.out.println("==protected==");
    }

    // 4、public: 本类,同一个包下的类,任意包下的子类,任意包下的任意类
    public void publicMethod(){
        System.out.println("==public==");
    }

    public void test(){
        //在本类中,所有权限都可以被访问到
        privateMethod(); //正确
        method(); //正确
        protectedMethod(); //正确
        publicMethod(); //正确
    }
}

测试在一个包下

public class Demo {
    public static void main(String[] args) {
        Fu f = new Fu();
        // f.privateMethod();        //私有方法无法使用
        f.method();
        f.protectedMethod();
        f.publicMethod();
    }
}

测试在另外一个包下

public class Zi extends Fu {
    //在不同包下的子类中,只能访问到public、protected修饰的方法
    public void test(){
        // privateMethod(); // 报错
        // method(); // 报错
        protectedMethod();        //正确
        publicMethod();        //正确
    }
}

父类不同包下

public class Demo2 {
    public static void main(String[] args) {
        Fu f = new Fu();
        // f.privateMethod(); // 报错
        // f.method();                  //报错
        // f.protecedMethod();//报错
        f.publicMethod();        //正确

        Zi zi = new Zi();
        // zi.protectedMethod();
    }
}

最后的注意事项:

java的继承是单继承,不支持多继承,但是支持多级继承

3.多态

所谓的多态,就是拿父类接受子类的对象

class Fu

class Zi extends Fu

//创建一个子类的对象正常需要用Zi这个类型去接收,如果用Fu类型去接收他,这种情况就是多态
Fu zi = new Zi()

3.1多态有啥用?

哎,其实没啥用啦,正常的咱也不写这个代码,哈哈!!!

  1. 代码重用性:通过多态性,可以在不修改已有代码的情况下,通过扩展已有类的功能来创建新类。这样可以提高代码的重用性,减少重复编写代码的工作量。

  2. 灵活性和可扩展性:多态性可以让程序具有更好的灵活性和可扩展性。通过接口或抽象类定义统一的方法,然后由不同的子类实现具体的行为。这样,我们可以通过增加新的子类来扩展系统的功能,而不需要修改已有的代码。

  3. 可替代性和可扩展性:多态性使得我们可以用一个通用的父类类型来引用不同子类的对象,从而实现了接口和实现类之间的可替代性。这样可以提高代码的灵活性和可维护性。

// 定义一个动物类
public class Animal {
        public  void sayHello(){
            System.out.println("怎么叫不知道哇");
        }
}

// 定义一个狗类,继承自动物类
class Dog extends Animal {
    @Override
    public void sayHello() {
        System.out.println("汪汪汪");
    }

    public void shakeTail() {
        System.out.println("摇尾巴");
    }
}

// 定义一个猫类,继承自动物类
class Cat extends Animal {
    @Override
    public void sayHello() {
        System.out.println("喵喵喵");
    }

    public void catchMouse() {
        System.out.println("捉老鼠");
    }
}


public class Test {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        animal1.sayHello(); // 输出:汪汪汪

        Animal animal2 = new Cat();
        animal2.sayHello(); // 输出:喵喵喵
    }
}

在上面的示例代码中,Animal 类是一个父类,定义了一个方法 sayHello()。然后通过继承 Animal 类来创建了 Dog 和 Cat 类,它们分别实现了自己的 sayHello() 方法,并且还有自己独有的方法 shakeTail()catchMouse()

不管创建什么子类的对象都可以用父类来引用,定义起来相对比较方便,并且只要是有类需要用这个方法,都可以直接继承这个父类,重写里面的方法(但是只能调用父类中有的方法)

当然,如果我们需要调用子类特有的方法(如 shakeTail()catchMouse()),则需要将父类的引用强制转换为子类的引用。但是这种做法存在风险,可能会导致运行时异常,因此需要谨慎使用。

3.2父类强制类型转换成子类

问题:用父类的引用指向子类的对象是不能调用子类特有的方法的,怎么解决呢?

public class Animal {
        public  void sayHello(){
            System.out.println("怎么叫不知道哇");
        }
}

// 定义一个狗类,继承自动物类
class Dog extends Animal {
    @Override
    public void sayHello() {
        System.out.println("汪汪汪");
    }

    public void shakeTail() {
        System.out.println("摇尾巴");
    }
}

// 定义一个猫类,继承自动物类
class Cat extends Animal {
    @Override
    public void sayHello() {
        System.out.println("喵喵喵");
    }

    public void catchMouse() {
        System.out.println("捉老鼠");
    }
}

如果将Animal类型向下转换成子类的话,就可以调用了

注意:转型的时候原本是什么类型,才能还原成什么类型

4.final关键字

final是一个关键字,可以用来修饰类,变量,方法

  • final修饰类:不能被继承

  • final修饰方法:不能被重写。

  • final修饰变量:不能修改变量对应的值

被final修饰的类不能被继承

被final修饰的方法不能被重写

 被final修饰的变量不能被重新赋值

被final修饰的变量=>常量

一般我们在记录一些几乎不会被修改的变量时会定义成常量,调用起来方便快捷又安全

public class Constant {
    //常量: 定义一个常量表示学校名称
    //为了方便在其他类中被访问所以一般还会加上public修饰符
    //常量命名规范:建议都采用大写字母命名,多个单词之前有_隔开
    public static final String SCHOOL_NAME = "多易教育";
    
    public static final String USER_NAME= "root";
    
     public static final String PASSWORD= "123456";
}


//测试调用
public class FinalDemo2 {
    public static void main(String[] args) {
        //由于常量是static的所以,在使用时直接用类名就可以调用
        System.out.println(Constant.SCHOOL_NAME);
        System.out.println(Constant.USER_NAME);
        System.out.println(Constant.PASSWORD);
    }
}

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值