QiYongchuan / MyGitBlog

个人博客主页,记录计算机学习,前端-后端-全栈学习ing
15 stars 0 forks source link

Java的一些基础知识点复习 #83

Open QiYongchuan opened 4 months ago

QiYongchuan commented 4 months ago

方法的重载 overload

定义:一个类中方法名字相同,但是参数列表不同的方法。

注意:重载的方法,就是不同的方法,只是名称相同而已。 image

    static void add(){

    }
    static void add(int a,int b)
    {
        System.out.println(a+b);
    }
    static void add(double a,double b)
    {
        System.out.println(a+b);
    }

当返回值不同时,但形参形同时,无法构成

static int add(int a,int b,int c){
System.out.println(a+b+c);
return a+b+c;
}
static double add(int a,int b,int c){
System.out.println(a+b+c);
return a+b+c;
}

方法的调用机制

  • 当程序执行到方法时,会在栈中单独开一个空间(栈空间)
  • 执行完毕,或者执行到return语句后,就会返回到 调用方法的地方
  • 同理,main方法栈执行完毕之后,栈空间也会回收,整个程序退出

image

方法的传参

可变参数

Java中允许同一个类中多个同名 同功能但是参数个数不同的方法,封装成一个方法。

==>对方法重载的一种优化,不用因为参数个数不同而写多个方法了 image

可以把传入的参数nums 视为数组

    public int getSum(int... nums) {
        System.out.println("参数的个数" + nums.length);
        int tolNums = 0;
        for (int i = 0; i < nums.length; i++) {

            tolNums += nums[i];
        }
        return tolNums;
    }
QiYongchuan commented 4 months ago

Java中的基本数据类型

byte: 8位有符号的补码整数,范围为-128到127。 short: 16位有符号的补码整数,范围为-32768到32767。 int: 32位有符号的补码整数,范围为-2^31到2^31-1。 long: 64位有符号的补码整数,范围为-2^63到2^63-1。 float: 单精度32位IEEE 754浮点数。 double: 双精度64位IEEE 754浮点数。 boolean: 逻辑类型,只能取两个值之一:true或false。 char: 单个16位Unicode字符,范围为'\u0000'到'\uffff'。 image

整数:byte、short、int、long 浮点数:float、double 字符:char 逻辑:boolean

image

基本数据类型的默认值如下:

byte: 0 short: 0 int: 0 long: 0L float: 0.0f double: 0.0d boolean: false char: '\u0000'

补充:所有的引用类型则是null

数据类型转换

image

public static void main(String[] args) {
        int num = 'a';  //   char --> int 97
        double d1 = 80;  // double -->  80.0

        System.out.println(num);
        System.out.println(d1);
    }

注: 1.混合多种类型时,转换为最高的类型 2.(byte,short)和char之间不会相互自动转换 3.byte,shoort,char 他们三者可以计算,计算时首先转化为int 再计算;另三种无论是单独还是混合都会提升。(精度提升到int)

强制类型转化:

基本数据类型与String类型的转换

QiYongchuan commented 4 months ago

OOP 面向对象编程

面向过程:适合简单、不需要协作的事务,重点关注如何执行

类比,如何把大象装进冰箱,1、2、3步,一步一步的执行,不需要过多的协作,一步一步就可以了

面向对象:宏观上把握,整体上分析整个系统;但具体到实现部分的操作的时候,仍然需要一步一步的考虑,也就是面向过程了。

两者是相辅相成,不可分开的:

具体概念

对象和类:类class是模板,是图纸,对象object(instance实例),对象是具体的体现,是实例。

类有三个成员:属性(field,也称为成员变量)、方法method、构造器constructor

属性即静态的数据,方法是动态的行为

属性(file 成员变量):用于定义该类或该类的对象包含数据,或者说静态特征,作用范围是整个类体,在定义成员变量时可以对其初始化,如果不对其初始化,java采用默认值对其初始化。

方法:用于定义该类或该类实例(对象)的行为特征和功能实现的。方法是类和对象行为特征的抽象。 因为在面向对象中,整个程序的基本单位是类,所以方法是从属于对象的。

public class Student {
    int id;
    int age;
    String name;

    public void study(){
        System.out.println("I am studying");
    }
    public void sleep(){
        System.out.println("I am sleeping");
    }

//实现一个对象,实例化一个对象,利用的是编译器自动生成构造函数 Study(){}
 public static void main(String[] args) {
        Student st1 = new Student();
        st1.id = 100;
        st1.age = 20;
        st1.name = "John";
        st1.study();
        st1.sleep();
    }
}

简单内存分析(帮助理解面向对象):

image

构造方法(构造器constructor) why ?

在创建的同时进行赋值 image 如果不写,则是默认的系统指定的无参构造器,无法在创建的时候进行赋值,只能等创建完成之后,再赋值;一旦构建了有参构造器后,默认的构造器就会被覆盖了,如果想用就必须再创建一个默认的无参构造器。

class Person{
String name;
int age;
public Person(String name1,int age1){
System.out.println("Constructor 被调用");
name = name1;
age = age1;
}
public Person(){
System.out.println("默认构造函数被调用");
}
}

构造器用于对象的初始化,而不是创建;

构造方法是装修房子,而不是创建房子

创建对象的四步:

  1. 分配对象空间,并对对象成员变量初始化为0或者空
  2. 执行属性值的显式初始化(即如果一开始的属性值给赋值后,就执行显示初始化,而不是默认值)
  3. 执行构造方法
  4. 返回对象的地址给相关的变量

image

构造器(构造方法)的四个要点:

public class Point {
   double x,y;

     Point(double i, double j) {
          x = i;
          y = j;
    }

构造方法重载

public class User {
    int age;
    String name;
    int pswd;

    public User(int age, String name, int pswd)
    {
        this.age = age;
        this.name = name;
        this.pswd = pswd;
    }
    public User()
    {
    }

对象创建流程详解:

  1. 加载类(Perseon.class)信息,只会加载一次
  2. 在堆中分配内存空间(地址)
  3. 在完成对象初始化
    • 3.1 默认初始化 age=0 name=null
    • 3.2 显式初始化 age=90 name=null
    • 3.3 构造器初始化 age=20,name=小倩
      1. 将对象在堆中分配到的内存地址,返回给p(p,就是对象名,也就是说是对象的引用)
QiYongchuan commented 4 months ago

JVM虚拟机内存模型 image

image

注意这里:
People p2 = p1   //执行的是将p1堆中的地址给了p2,

而
People p2 = new People()  则是实现了在堆中新建一个地址区

image

image

 public static void main(String[] args) {

        People p1 = new People();
        p1.age = 10;
        People p2 = p1;
        System.out.println(p2.age);  //10
        p2.age = 20;
        System.out.println(p1.age);  //20
    }

本质:两者是同一个引用地址

垃圾回收:

image 为什么 b.age 会报错?

将b设置为null,断开了b与Person对象的连接。在Java中,设置为null意味着引用不再指向任何对象,但由于a仍然指向那个对象,所以那个对象不会被垃圾回收器回收。

尝试打印b.age,但是会抛出NullPointerException,因为b已经被设置为null,不再指向任何对象。

System.out.println(b.age); // 抛出NullPointerException

image

区分:

image

这里p=null指向空,栈中test200中的p空了,但是main中的p.age依然指向原来的地址(堆中的地址p)

QiYongchuan commented 4 months ago

作用域 变量的范围。 Java中变量一般分为:属性和成员方法中的变量,即分别是全局变量和局部变量。

补充:

区别:

修饰符:

QiYongchuan commented 4 months ago

this关键字 why? 区分当前类的属性和局部变量而引入。

//访问成员方法的语法  this.f
class T{
    public void f1(){
        System.out.println("f1() 方法");
    }

    public void f2(){
        System.out.println("f2() 方法");

        //调用本类的f1()方法
        //第一种方式
        f1();
        //第二种方式
        this.f1();
    }
}

构造器中使用this 注:仅限在构造器中使用,且this要放在第一条语句 image

this访问属性的区别: 如果没有this时,在成员方法中访问属性时采用就近原则(即有局部变量先访问局部变量,没有时访问全局变量),但是有this时,就只访问全局变量了。 image

image 答案10,9,10 涉及匿名对象,创建之后就销毁了 以及count++ 是后加加,先输出之后,后加

image

QiYongchuan commented 3 months ago

包 package why? 包的三大作用:

本质:创建不同的文件夹/目录,来保存文件 image

image

QiYongchuan commented 3 months ago

访问修饰符 用于控制方法和属性(成员变量)的访问权限(访问范围)。

image image

QiYongchuan commented 3 months ago

封装 面向对象的三大特征:封装、继承、多态 封装:把抽象出来的数据(属性)和对对象的操作(方法)封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(方法),才能对数据进行操作。

image

如何实现? image

image

构造器与setxx

image 因为当只写构造器时,可以在初始化时直接赋值,这样就绕过了set设置的规则;此时如果想继续保证set的效果,就将构造器与set结合,在构造器中调用set,这样即使是初始化赋值给的值不符合要求,就无法绕过set了。

QiYongchuan commented 3 months ago

继承 why ? 当两个类的属性和方法很多是相同的时候,怎么办 ==》继承,提高代码复用性 、

image image

好处:

继承细节点:

在子类创建时,子类的构造器默认调用了super()方法:本质是调用父类的无参构造器。

*当创建子类时,无论调用子类的哪一个构造器,默认情况下总会调用父类的无参构造器;

java中所有类都是Objece类的子类,Object类是所有类的基类(父类) 父类构造器的调用不限于直接的父类,将会一直往上追溯到Object类(顶级父类)

image image 单继承机制,只能一个父类;如果想继承C,可以先让B继承C,A就继承到了C.

QiYongchuan commented 3 months ago

继承的本质 ==>逐层向上的查找关系

image image image image

关键: 不要忘记了所有的构造器都有默认的super() super("hhh")显示调用,并传参

QiYongchuan commented 3 months ago

supper关键字 两个用途:

image

调用父类的构造器:当使用super()时,它必须是子类构造器中的第一条语句。这样做是为了确保在子类对象实例化过程中,父类的构造器首先被调用,以正确初始化继承自父类的属性。如果子类的构造器没有显式调用super(),编译器将自动插入一个无参的super()调用,前提是父类有一个无参构造器。

访问父类的成员(属性和方法):在子类的任何方法(包括构造器)内,可以使用super.属性或super.方法名()的形式访问父类的属性和方法。这在以下几种情况下特别有用:

当子类需要覆盖(Override)父类的方法,但在新方法中仍然想要调用父类中被覆盖的方法。 当子类的字段隐藏(Hide)了父类的同名字段,但需要访问父类中被隐藏的字段。 因此,super()用于构造器中调用父类的构造器,且必须是第一行代码;而super.属性或super.方法()可用于子类的任何其他方法中调用父类的成员,不受位置限制。

为什么需要super 访问父类的方法和属性?

类中 方法调用的逻辑

image

属性的访问逻辑:

image

image

本质:继承的本质==>向上查找,以及通过super.[属性/方法] 访问直接访问父类

image

image

QiYongchuan commented 3 months ago

方法的重写/覆盖override

image image

注意:

image

QiYongchuan commented 3 months ago

多态polymorphic 方法和对象具有多种形态,是面向对象的第三大特征,多态是建立在封装和继承基础之上的。 why? 当类越来越多时,传统方法,代码复用性不高,且不利于维护

  1. 方法的多态: (方法的重写和重载就体现了多态) image

2.对象的多态

image image

image 向上转型: 本质:父类的引用指向了子类的对象 Animal animal = new Dog(); //animal 编译类型就是Animal,运行类型就是Dog animal.cry(); //运行时,执行的是子类的cry(),因为animal的运行类型就是Dog,所以cry就是Dog的cry

向上转型的规则

多态的向下转型

image

image

属性重写问题

image

第一个例子向上转型后,base.count 时,此时的编译类型是Base 父类,所以base.count直接从父类查找,即10 第二个例子,不是向上转型,sub.count 遵循属性查找规则,先找本类,有,即20

QiYongchuan commented 3 months ago

练习: image

注意最后的b.display(); 方法运行看运行类型,此时b的运行类型是s,所以执行s的方法,输出的是20

QiYongchuan commented 3 months ago

java的动态绑定机制 image image 详解

多态的应用2:多态参数

image

QiYongchuan commented 3 months ago

object类详解

image equal和 == 的区别 image 区别:

image image image

image

QiYongchuan commented 3 months ago

Hashcode image

toString image image image

重写: image

finalize

image image

image

QiYongchuan commented 3 months ago

类变量(静态变量) 最大的特点就是可以被类的所有实例共享。 所有的对象都共享的空间(在堆中单独的空间),都拥有的对象

image

访问: 类名.类变量名(推荐) 或者:对象名.类变量名

image image

QiYongchuan commented 3 months ago

类方法(静态方法)

类的方法,可被所有的成员对象共享、调用;

image image

类方法的经典使用场景:

image image

image image

QiYongchuan commented 3 months ago

main方法

image

image

QiYongchuan commented 3 months ago

代码块 image

image image

image

补充细节:静态代码块与普通代码块 image

当同时有静态属性初始化和静态代码块时: image

注意:构造器是最后执行的

当涉及继承时: 构造器内默认隐藏的两步:

综合案例 image

1.先加载类 1.1 加载父类的静态属性以及代码块 1.2 再加载子类静态属性以及代码块 2.再加载对象 2.1 执行子类的构造器super() 2.2 在执行子类构造器之前,隐藏了父类的super(),以及父类的普通代码块和普通属性的初始化操作,的执行 2.3 执行完2.2,相当于执行完了子类super之前的隐藏的东西,现在 执行子类的普通代码块以及普通属性的初始化(看代码顺序了) 2.4 再执行完子类构造器中的剩余内容

image

练习题: image

注意:z在类调用时,完成静态属性和静态 代码块的加载;同时,静态代码块只执行一次;

QiYongchuan commented 3 months ago

单例设计模式

image image

QiYongchuan commented 3 months ago

final -- 常量 当不希望类被继承、或者方法被重写时 image

赋值的地方有三个:

如果final修饰的属性是静态的,则初始化的位置只能是: 1.在定义时 2.在静态代码块中

不能在构造器中(因为此时static加载是在类时,而构造器则是在实例化的时候) image

当只想要某个值,但是不需要类加载时,可以同时使用final和static image

QiYongchuan commented 3 months ago

抽象类 当父类有方法,但是暂时不确定时。

抽象方法,就是没有实现的方法,即没有方法体的方法 image image image

public abstract void eat()

细节:

image

QiYongchuan commented 3 months ago

接口 image 在接口中抽象方法可以省略abstract

interface中可以写属性以及方法,方法只能有以下三种:

image

QiYongchuan commented 3 months ago

内部类 属性、方法、构造器、代码块、内部类 嵌套在一个类中的类,被称为内部类。

image image image image

内部类分为四类:

1.局部内部类定义在方法中/代码块中 2.作用域在方法体里或代码中【也就是说内部类,只能在方法体中使用】 3.本质仍然是一个类 4.可以访问外部类的所有成员,包括私有的

image

匿名内部类

image

WHY? 什么时候会需要以及产生内部类? ==> 匿名内部类是用来简化开发的,匿名其实是系统自动分配一个用户看不到的名字的内部类,用来实例化

使用场景:基于接口的内部类 1.当我们想实现一个接口的方法,但不想创建一个新的类时,

IA tiger =new IA(){  // 注意:这里的编译类型是IA 接口, 运行类似就是**匿名内部类**,
此时是编译器自动执行的。
 new ==>jdk底层在创建匿名内部类的时候,也同时创建了实例,并且把实例返回给了tiger
@Overwride
//实现接口的方法
}

image

2.基于类的匿名内部类 即原来有一个类,如果要继承之后重写,需要新建一个类,现在可以直接使用匿名的内部类来实现 如何写?

原来new一个对象,只需要 Father father = new Father(); 就可以,如何使用匿名内部类,则需要: Father father = new Father(){}; // 注意,多了对象的{},如果是抽象的父类,就需要重写抽象方法了

image

匿名内部类的最佳实践: 当作实参直接传递 代码简洁高效

QiYongchuan commented 3 months ago

3.成员内部类
放在成员位置

image

如何使用成员内部类的方法呢?

public class Homework07 {
    public static void main(String[] args) {
        Car car1 = new Car(60);
        car1.getAir().flow();
    }
}

class Car{
    private double temperature;

    public Car(double temperature) {
        this.temperature = temperature;
    }

    class Air{
        public void flow(){
            if (temperature < 0){
                System.out.println("吹暖风");
            } else if (temperature > 40) {
                System.out.println("吹冷风");
            } else if (temperature > 0 && temperature < 40){
                System.out.println("空调关闭");
            }
        }
    }
   // 成员内部类如何调用方法
    public Air getAir(){
        return  new  Air();
    }
}

4.静态内部类

image

image

小结:

  1. 内部类有四种:局部内部类、匿名内部类、成员内部类、静态内部类
  2. 最重要的是匿名内部类: new 类/接口(参数列表){};
  3. 成员内部类和静态内部类,是放在外部类的成员位置,本质是一个成员。

练习题: image image

QiYongchuan commented 3 months ago

Java枚举类 why? image

枚举的实现方式: 1.自定义实现 2.使用 enum 关键字实现枚举

如何自定义实现枚举类? 1.将构造器私有化,这样就保证了无法在外部直接new的方式创建对象 2.去掉setXxx方法,防止属性被修改 3.在Season内部,直接创建固定的对象 4.优化,可以加入final修饰符,类不用加载了

image image

使用关键字enum 来创建:

image

一些细节: image 这里,如果实例化调用无参构造器时,可以只写常量名,把后面的()也省略掉; 比如下面: image

例题:

image image

image 这里w为什么是True? 因为Gender2.BOY 是一个静态对象,所以boy和boy2是相同的一个,所以是True

enum类的常用方法

image image image 可以实现j接口 不能继承其它类了,因为本身隐式继承了Enum类了(java单继承机制,即只能有一个直接的父类)

补充知识点:增强for循环 image image image

QiYongchuan commented 3 months ago

注解 Jdk的基本注解内容:

image image

image image

相当于做了一个语法的校验,加强检查的功能了。

deprecated 用于提醒,版本升级时的过渡使用 image

suppresswaring 抑制警告

QiYongchuan commented 3 months ago

练习题 1. image 静态变量:只执行一次,所有在第二次创建对象初始化的时候,静态变量还保留着第一次初始化后修改的属性,所以颜色也是red

QiYongchuan commented 3 months ago

异常 Exception 意义在于让程序继续执行,而不是崩溃。

错误 Error -- java虚拟机无法解决的严重问题 image

异常又分为:编译时异常和运行时异常 image

image

编译异常

异常 Exception 意义在于让程序继续执行,而不是崩溃。

错误 Error -- java虚拟机无法解决的严重问题 image

异常又分为:编译时异常和运行时异常 image

image

编译异常

QiYongchuan commented 3 months ago

image

新建数组,但是是空数组,所以一开始就是空指针异常,到return 3 然后执行finally return 4; 最终的结果就是return 4

image 注意这里最后的返回值,与打印值。 finally没有返回值,只有打印值。

QiYongchuan commented 3 months ago

总结:异常分编译异常和运行异常,而编译异常必须处理(try catch 或者throw);而运行异常默认处理,不需要显式处理。

常见的编译异常和运行异常 编译异常:FileNOTFound、ClassNotFound 运行异常:除零异常/空指针异常 image

QiYongchuan commented 3 months ago

自定义异常 throw