java-面向对象-细节-重点

可变参数

  • 可变参数用类型...定义,可变参数相当于数组类型,可以传入一个数组给方法中的可变参数。

  • 完全可以把可变参数改写为String[]类型,但是,调用方需要自己先构造String[],比较麻烦。

class Group {
    private String[] names;
    
    public void setNames1(String... names){
        this.names = names;
    }
    public void setNames2(String [] names){
        this.names = names;
    }
}

//调用
Group g = new Group();
g.setNames1("Xiao Ming", "Xiao Hong", "Xiao Jun");
g.setNames1(); //为空,传入0个String,不为null
g.setNames2(new String[] {"Xiao Ming", "Xiao Hong", "Xiao Jun"}); //需要构造数组
g.setNames2(null); //接收到一个null值

可变参数可以保证无法传入null,因为传入0个参数时,接收到的实际值是一个空数组而不是null

方法重载

方法名相同,但各自的参数不同,称为方法重载(Overload)。

继承

  • 继承树:在Java中,没有明确写extends的类,编译器会自动加上extends Object。所以,任何类,除了Object,都会继承自某个类。

  • Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,它没有父类。

  • 继承有个特点,就是子类无法访问父类的private字段或者private方法,但可以通过父类的set、get方法访问父类的私有属性。

  • 为了让子类可以访问父类的字段,我们可以把private改为protected。用protected修饰的字段可以被子类访问。

向上转型
  • 一个引用类型为一个类的父类的变量,可以指向子类的实例。

  • 这种把一个子类类型变为父类类型的赋值,被称为向上转型(upcasting),向上转型实际上是把一个子类型安全地变为更抽象的父类型。

向下转型
  • 和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。

  • 如果一个类的实际类型是父类,不能把父类变成子类,因为子类功能比父类多,多的功能无法凭空变出来。

  • 因此,向下转型很可能会失败,JVM报错ClassCastException

  • 为了避免向下转型出错,java提供了instanceof操作符,可以先判断一个实例究竟是不是某种类型:

    注:如果一个类是子类,那么这个类也拥有了父类的非私有字段和方法,所以这个类也算一个父类。

    Person p = new Person();
    System.out.println(p instanceof Person); // true
    System.out.println(p instanceof Student); // false
    
    Student s = new Student();
    System.out.println(s instanceof Person); // true
    System.out.println(s instanceof Student); // true
    
  • Java14开始,判断instanceof后,可以直接转型为指定变量,避免再次强制转型。

    Object obj = "hello";
    if (obj instanceof String) {
        String s = (String) obj;
        System.out.println(s.toUpperCase());
    }
    可以改写为以下代码:
    Object obj = "hello";
    if (obj instanceof String s) {
        // 可以直接使用变量s:
        System.out.println(s.toUpperCase());
    }
    
  • 子类可以直接通过super(Object o,...)直接调用父类的构造方法(只能在子类的构造方法中调用父类的构造方法)。

        public Student(String name, int age, int score) {
            super(name, age);
            this.score = score;
        }
    
super

在子类的方法中,如果要调用父类的非私有方法,可以通过super来调用。

super.hello()即是调用父类的hello()方法。

重写

  • 在继承关系中,如果子类定义了一个与父类方法签名完全相同的方法,被称为覆写/重写(Override)。

    方法签名:方法名,参数列表类型和顺序。(不包括返回类型、形参名)

    返回类型不同则代表不是同一个方法,不同方法就不能有相同命名。

    在子类中重写父类的私有方法的时候不能加上重写的注解,因为无法访问到父类的私有方法,重写父类的私有方法相当于在子类中添加子类特有的方法,所以不能称之为重写

  • 加上@Override可以让编译器帮助检查是否进行了正确的覆写,不是覆写的话会报compile error。

  • Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。

    解释:如果一个子类重写了父类的方法,该子类的一个实例的引用类型是父类,如果调用该实例的重写方法,实际上会调用子类重写后的方法。(即实际类型的方法)

  • 子类重写父类的方法不能设为私有,因为需要通过父类进行访问,否则没有意义。

final

final修饰的方法不能被Override

final修饰的类不能被继承。

final修饰的字段在初始化后不能被修改。

final字段重新赋值会报错。

可以在构造方法中初始化final字段,

class Person {
    public final String name; //实例一旦创建,final字段就不可修改。
    public Person(String name) {
        this.name = name;
    }
}

多态

多态是指针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法

例子:普通收入、工资收入、国务院津贴。

public class Main {
    public static void main(String[] args) {
        // 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
        Income[] incomes = new Income[] {
            new Income(3000),
            new Salary(7500),
            new StateCouncilSpecialAllowance(15000)
        };
        System.out.println(totalTax(incomes));
    }
	// 该方法只需要接收Income对象,就可以根据传入的对象做不同的处理。
    public static double totalTax(Income... incomes) {
        double total = 0;
        for (Income income: incomes) {
            total = total + income.getTax();
        }
        return total;
    }
}

class Income {
    protected double income;

    public Income(double income) {
        this.income = income;
    }

    public double getTax() {
        return income * 0.1; // 税率10%
    }
}

class Salary extends Income {
    public Salary(double income) {
        super(income);
    }

    @Override
    public double getTax() {
        if (income <= 5000) {
            return 0;
        }
        return (income - 5000) * 0.2; //减去基数再×税率
    }
}

class StateCouncilSpecialAllowance extends Income {
    public StateCouncilSpecialAllowance(double income) {
        super(income);
    }

    @Override
    public double getTax() {
        return 0;	//不用交税。
    }
}
覆写Object方法

因为所有的class最终都继承自Object,而Object定义了几个重要的方法:

  • toString():把instance输出为String
  • equals():判断两个instance是否逻辑相等;
  • hashCode():计算一个instance的哈希值。
class Person {
    ...
    // 显示更有意义的字符串:
    @Override
    public String toString() {
        return "Person:name=" + name;
    }

    // 比较是否相等:
    @Override
    public boolean equals(Object o) {
        // 当且仅当o为Person类型:
        if (o instanceof Person) {
            Person p = (Person) o;
            // 并且name字段相同时,返回true:
            return this.name.equals(p.name);
        }
        return false;
    }

    // 计算hash:
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
}

抽象类

  • 如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,目的是让子类去覆写它,那么,可以把父类的方法声明为抽象方法。

  • 把一个方法声明为abstract,表示它是一个抽象方法,本身没有实现任何方法语句。

  • 带有抽象方法的类也无法被实例化

面向抽象编程

引用高层类型(父类),避免引用实际子类型的方式,称之为面向抽象编程。

面向抽象编程的本质就是:

  • 上层代码只定义规范(例如:abstract class Person);
  • 不需要子类就可以实现业务逻辑(正常编译);
  • 具体的业务逻辑由不同的子类实现,调用者并不关心。

接口

  • 如果一个抽象类没有字段,所有方法全部都是抽象方法,就可以把该抽象类改写为接口:interface

  • 接口定义的所有方法默认都是public abstract的。

  • 接口定义的成员变量默认都是public static final

  • 在Java中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个interface

  • 如果一个类实现了多个接口,其中两个接口具有相同的方法签名但返回类型不同,此时需要重写的方法返回类型不确定,不能这样实现。(即一个类不能实现一个具有不同返回类型但具有相同方法签名方法的接口),但是如果返回类型的一个是另一个的子类型,那么可以重写返回类型为子类型的方法。

抽象类和接口的对比如下:

abstract classinterface
继承只能extends一个class可以implements多个interface
字段可以定义实例字段不能定义实例字段
抽象方法可以定义抽象方法可以定义抽象方法
非抽象方法可以定义非抽象方法可以定义default方法
接口继承
  • 一个interface可以继承自另一个或多个interfaceinterface继承自interface使用extends,它相当于扩展了接口的方法。
继承关系
  • 在使用的时候,实例化的对象永远只能是某个具体的子类,但总是通过接口去引用它,因为接口比抽象类更抽象。
default方法
  • 在接口中,可以定义default方法。

  • 实现类可以不必覆写default方法。default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改。

  • default方法和抽象类的普通方法是有所不同的。因为interface没有字段,default方法无法访问字段,而抽象类的普通方法可以访问实例字段。

  • 如果一个类实现了多个接口,其中两个接口具有相同的方法签名的default方法,那么该类必须重写该方法。

静态字段和静态方法

静态字段
  • static修饰的字段,称为静态字段:static field

  • 实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段。

不推荐用实例变量.静态字段去访问静态字段。因为在Java程序中,实例对象并没有静态字段。在代码中,实例对象能访问静态字段只是因为编译器可以根据实例类型自动转换类名.静态字段来访问静态对象。

静态方法
  • static修饰的方法称为静态方法。

  • 调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用。

  • 静态方法属于class而不属于实例,因此,静态方法内部,无法访问this变量,也无法访问实例字段,它只能访问静态字段

  • 在Java中,我们使用package来解决名字冲突。

  • 在Java虚拟机执行的时候,JVM只看完整类名,因此,只要包名不同,类就不同。

  • import static的语法,它可以导入可以导入一个类的静态字段和静态方法(很少用)。

  • 注意包不能重名。

要特别注意:包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系。

包作用域
  • 位于同一个包的类,可以访问包作用域的字段和方法。不用publicprotectedprivate修饰的字段和方法就是包作用域。

作用域

public

定义为publicclassinterface可以被其他任何类访问。

定义为publicfieldmethod可以被其他类访问,前提是首先有访问class的权限。

private

定义为privatefieldmethod无法被其他类访问。

阅读代码的时候,应该先关注public方法。

嵌套类

定义在一个class内部的class称为嵌套类(nested class),嵌套类拥有访问其外层的private的权限。

protected

protected作用于继承关系。定义为protected的字段和方法可以被子类访问,以及子类的子类。

final

final修饰class可以阻止被继承。

final修饰method可以阻止被子类覆写。

final修饰field可以阻止被重新赋值。

final修饰 局部变量/方法参数 可以阻止被重新赋值。

  • 如果不确定是否需要public,就不声明为public,即尽可能少地暴露对外的字段和方法。

  • 一个.java文件只能包含一个public类,但可以包含多个非public类。如果有public类,文件名必须和public类的名字相同。

classpath和jar

  • classpath是JVM用到的一个环境变量,它用来指示JVM如何搜索class

  • Java是编译型语言,源码文件是.java,而编译后的.class文件才是真正可以被JVM执行的字节码。

  • jar包相当于目录,可以包含很多.class文件,方便下载和使用;

模块

从Java 9开始,JDK又引入了模块(Module)。

  • .class文件是JVM看到的最小可执行文件,而一个大型程序需要编写很多Class,并生成一堆.class文件,很不便于管理,所以,jar文件就是class文件的容器。

  • 如果是自己开发的程序,除了一个自己的app.jar以外,还需要一堆第三方的jar包,运行一个Java程序,一般来说,命令行写这样:

java -cp app.jar:a.jar:b.jar:c.jar com.liaoxuefeng.sample.Main
  • 如果漏写了某个运行时需要用到的jar,那么在运行期极有可能抛出ClassNotFoundException。所以,jar只是用于存放class的容器,它并不关心class之间的依赖

`文件,方便下载和使用;

模块

从Java 9开始,JDK又引入了模块(Module)。

  • .class文件是JVM看到的最小可执行文件,而一个大型程序需要编写很多Class,并生成一堆.class文件,很不便于管理,所以,jar文件就是class文件的容器。

  • 如果是自己开发的程序,除了一个自己的app.jar以外,还需要一堆第三方的jar包,运行一个Java程序,一般来说,命令行写这样:

java -cp app.jar:a.jar:b.jar:c.jar com.liaoxuefeng.sample.Main
  • 如果漏写了某个运行时需要用到的jar,那么在运行期极有可能抛出ClassNotFoundException。所以,jar只是用于存放class的容器,它并不关心class之间的依赖

  • 从Java 9开始引入的模块主要就是为了解决“依赖”这个问题。如果a.jar必须依赖另一个b.jar才能运行,那我们应该给a.jar加点说明,让程序在编译和运行的时候能自动定位到b.jar,这种自带“依赖关系”的class容器就是模块。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象是一种程序设计的思想,它将程序中的数据和对数据的操作封装在一起,形成对象。对象是类的一个实例,类定义了对象的属性和行为。在Java中,面向对象的概念包括类与对象的关系、封装、构造函数、this关键字、static关键字以及设计模式等方面。 设计模式是在软件设计中常用的解决问题的经验总结,它提供了一套可重用的解决方案。在Java中,单例设计模式是一种常见的设计模式之一,它保证一个类只有一个实例,并提供一个全局访问点。通过使用单例设计模式,可以确保在程序中只有一个对象实例被创建,从而节省了系统资源并提高了性能。 通过使用单例设计模式,可以实现以下效果: - 限制一个类只能有一个实例。 - 提供一个全局访问点,使其他对象可以方便地访问该实例。 - 保证对象的唯一性,避免多个对象的状态不一致。 在Java中,实现单例设计模式有多种方式,包括饿汉式、懒汉式、双重检测锁等。每种方式都有各自的特点和适用场景,开发者可以根据具体的需求选择合适的实现方式。设计模式是一种通用的解决问题的方法,它可以在面向对象的程序设计中提供灵活、可复用的解决方案。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [计算机后端-Java-Java核心基础-第15章 面向对象07 14. 设计模式与单例设计模式.avi](https://download.csdn.net/download/programxh/85435560)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [完整版Java全套入门培训课件 Java基础 03-面向对象(共18页).pptx](https://download.csdn.net/download/qq_27595745/21440470)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值