学了一部分才开的个人博客并开始使用markdown写笔记,前面的笔记就不补了。


Chapter 07

可变参数

  • 可变参数的使用:

    可变参数示例:

    1
    2
    3
    4
    5
    6
    /**
    * 实现多个参数求和
    */
    public int sum(int... nums){
    //方法体
    }

    代码解读:

    1.int… 表示接收的是可变参数,类型是int,可以接收多个int类型参数。

    2.使用可变参数时,可以当作数组来使用。

    3.遍历nums求和。

  • 注意事项和使用细节:

    1.可变参数的实参可以为数组。

    2.可变参数的本质就是数组。

    3.可变参数可以和普通类型的参数一起放在形参列表,但是需要保证可变参数在最后

    1
    2
    3
    4
    5
    6
    /**
    * 示例
    */
    public void f(String str,double... nums){
    //方法体
    }

    4.一个形参列表中只能出现一个可变参数。

作用域

  • 作用域的基本使用:

    1.局部变量:一般指在成员方法中定义的变量,是除了属性之外的其他变量,作用域为定义它的代码块中。局部变量赋值后才可以使用,即无默认值。

    2.全局变量:即属性,作用域为整个类体。全局变量可以不赋值,直接使用(默认值)。

  • 注意事项和使用细节:

    1.属性和局部变量可以重名,访问时遵循就近原则

    2.在同一个作用域中,两个局部变量不能重名。

    3.属性生命周期较长:伴随对象;局部变量生命周期较短:伴随代码块。

    4.属性不仅可以被本类使用,也可以被其他类使用(通过对象调用);局部变量只能在本类的对应方法中使用。

    5.属性可以加修饰符,局部变量不可以加修饰符。

构造方法/构造器

基本语法:

[修饰符] 方法名(形参列表){

​ 方法体;

}

说明:

1.构造器的修饰符可以默认。

2.构造器没有返回值

3.方法名必须和类的名字一致。

4.参数列表的规则和成员方法相同。

5.构造器的调用由系统完成。

主要作用:完成对新对象的初始化

  • 快速入门:

    示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /**
    * 创建Person对象时,就直接指定这个对象的年龄和姓名
    */
    public class Example{
    public static void main(String[] args){
    //当我们创建一个对象时,直接通过构造器指定名字和年龄
    Person p1 = new Person("Smith",80);
    }
    }

    class Person{
    String name;
    int age;
    public Person(String pName,int pAge){
    name = pName;
    age = pAge;
    }
    }

    解读:

    1.构造器没有返回值**(也不能返回void类型)**

  • 注意事项和使用细节:

    1.一个类可以定义多个不同的构造器,即构造器的重载。

    2.构造器是完成对象的初始化的,不是创造对象

    3.创建对象时,系统自动的调用该类的构造方法。

    4.如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器)。

    5.一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非自己显式定义无参构造器。

    无参构造器语法:

    方法名(){

    }

对象创建的流程分析

案例:

1
2
3
4
5
6
7
8
9
class Person{
int age = 90;
String name;
Person(String n,int a){
name = n;
age = a;
}
}
Person p = new Person("小明",20);
  • 流程分析:

    1.加载Person类信息(Person.class),只会加载一次

    2.在堆中分配空间(地址)。

    3.完成对象初始化:

    • 默认初始化。(age = 0,name = null)
    • 显式初始化。(age = 90,name = null)
    • 构造器的初始化。(age = 20,name = 小明)

    4.将对象在堆中的地址返回给p(p是对象名,也可以理解为对象的引用)。

this关键字

this代表当前对象。

  • 注意事项和使用细节:

    1.this关键字可以用来访问本类的属性、方法、构造器。

    2.this用于区分当前类的属性和局部变量。

    3.this关键字访问成员方法的语法:

    this.方法名(参数列表);

    4.this关键字访问构造器的语法:只能在构造器中访问另一个构造器,不可以在普通方法中使用。

    this(参数列表);

    该语句要使用,则必须放在构造器的第一句

    5.this不能在类定义的外部使用,只能在类定义的方法中使用

Chapter 08

  • 作用:

    1.区分相同名字的类。

    2.当类很多时,可以很好的管理类。

    3.控制访问范围。

基本语法:

package 包名;

  • 本质:创建不同文件夹来保存类文件。

  • 包的命名:

    1.命名规则:只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或保留字。

    2.命名规范:一般是小写字母+小圆点

    com.公司名.项目名.业务模块名

  • 常用的包:

    1.java.lang.*:是基本包,默认引入。

    2.java.util.*:系统提供的工具包、工具类。

    3.java.net.*:网络包,网络开发。

    4.java.awt.*:做java的界面开发,GUI。

  • 如何引入包:

    语法:

    import 包;

    示例

    import java.util.Scanner; 只是引入Scanner类。

    import java.util.*; 将java.util包的所有类都引入。

  • 注意事项和使用细节:

    1.package的作用是声明当前类所在的包,需要放在class的最上面,一个类中最多只有一句package

    2.import指令放在package下面,在类定义前面,可以有多句且没有顺序要求。

访问修饰符

  • 基本介绍:用于控制方法和属性(成员变量)的访问权限(范围)。

    1.公开级别:用public修饰,对外公开。

    2.受保护级别:用protected修饰,对子类和同一个包中的类公开。

    3.默认级别:没有修饰符号,向同一个包的类公开。

    4.私有级别:用private修饰,只有类本身可以访问,不对外公开。

  • 4种访问修饰符的访问范围:

    访问级别 访问控制修饰符 同类 同包 子类 不同包
    公开 public
    受保护 protected ×
    默认 没有修饰符 × ×
    私有 private × × ×
  • 使用的注意事项:

    1.修饰符可以用来修饰类中的属性、成员方法以及类。

    2.只有默认和public才能修饰类,并且遵守上述访问权限的特点。

    3.成员方法的访问规则和属性完全一样。

封装

  • 优点:

    1.隐藏实现细节。

    2.可以对数据进行验证,保证安全合理。

  • 封装实现的步骤:

    1.将属性进行私有化**(不能直接修改属性)**。

    2.提供一个公共的set方法,用于对属性判断并赋值。

    如果使用构造器且需要验证属性,则可以在构造器中使用set方法。

    public void setXxx(类型 参数名){ //Xxx表示某个属性

    ​ //加入数据验证的业务逻辑

    ​ 属性 = 参数名;

    }

    3.提供一个公共的get方法,用于获取属性的值。

    public XX getXxx{ //权限判断

    ​ return xx;

    }

继承

  • 基本介绍:

    继承可以解决代码复用。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(基类)。在父类(基类)中定义这些相同的属性和方法,所有的子类(派生类)不需要重新定义这些属性和方法,只需要通过extends来声明继承父类(基类)即可。

  • 基本语法:

    class 子类 extends 父类{

    }

  • 注意事项和使用细节:

    1.子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问(可以间接访问),要通过父类提供公共的方法(get方法)去访问。

    2.子类必须调用父类的构造器,完成父类的初始化。

    3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器。如果父类没有提供无参构造器,则必须在子类的构造器中用super(参数列表)去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不会通过

    4.如果希望指定去调用父类的某个构造器,则显式调用super()

    5.super在使用时,必须放在构造器第一行。(super只能在构造器中使用)

    6.super()this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器中

    7.Java所有类都是Object类的子类。

    8.父类构造器的调用不限于直接父类,将一直往上追溯直到Object类。

    9.子类最多只能直接继承一个父类,即Java中是单继承机制

    10.不能滥用继承,子类和父类之间必须满足is-a的逻辑关系。

  • 本质分析:按照查找关系来返回信息

    1.首先看子类是否有该属性。

    2.如果子类有这个属性,并且可以访问,则返回信息;如果子类没有这个属性,则看父类有没有这个属性(如果父类有该属性,并且可以访问,则返回信息)。

    3.如果父类没有该属性,则按照2的规则,继续找上级父类,直到Object类。

    如果在查找过程中找到了该属性,但是无法访问,则直接报错。

super关键字

  • 基本介绍:

    super代表父类的引用,用于访问父类的属性、方法、构造器。

  • 基本语法:

    1.访问父类的属性,但不能访问父类的private属性。

    super.属性名;

    2.访问父类的方法,不能访问父类的private方法。

    super.方法名(参数列表);

    3.访问父类的构造器(只能放在构造器的第一句)。

    super(参数列表);

  • 注意事项和使用细节:

    1.当子类中有和父类中成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super(直接查找父类)this(先查找本类)、直接访问是一样的。

    2.super的访问不限于直接父类,如果间接父类和本类中有同名的成员,也可以用super去访问间接父类的成员。如果多个基类中都有同名成员,使用super访问时,遵循就近原则。(也要遵守访问权限的相关规则)

super和this的比较

区别点 this super
访问属性 访问本类中的属性,如果本类没有此属性,则从父类中继续查找。 访问父类中的属性。
调用方法 访问本类中的方法,如果本类没有此方法,则从父类中继续查找。 直接访问父类中的方法。
调用构造器 调用本类构造器,必须放在构造器的首行。 调用父类构造器,必须放在子类构造器的首行。
特殊 表示当前对象。 子类中访问父类对象。

方法重写/覆盖

子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法。

  • 注意事项和使用细节:

    1.子类的方法的形参列表、方法名称要和父类方法的形参列表、方法名称完全一样。

    2.子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类。

    3.子类方法不能缩小父类方法的访问权限(可以扩大)。

方法重写和重载的比较

名称 发生范围 方法名 形参列表 返回类型 修饰符
重载(overload) 本类 必须一样 类型、个数或者顺序,至少有一个不同 无要求 无要求
重写(override) 父、子类 必须一样 必须相同 子类重写的方法返回的类型和父类返回的类型一致,或者是其子类 子类方法不能缩小父类方法的访问范围

多态

  • 基本介绍:

    方法或对象具有多种形态,建立在封装和继承的基础之上。

  • 具体体现:

    1.方法的多态。(重写和重载均体现多态)

    2.对象的多态

    • 一个对象的编译类型和运行类型可以不一致。
    • 编译类型在定义对象时就确定了,不能改变。
    • 运行类型是可以变化的。
    • 编译类型看定义时=的左边,运行类型看=的右边。
  • 多态的向上转型

    1.本质:父类的引用指向了子类的对象。

    2.语法:

    父类类型 引用名 = new 子类类型();

    3.特点:

    • 编译类型看左边,运行类型看右边。

    • 可以调用父类中的所有成员(需遵循访问权限)。

    • 不能调用子类中的特有成员。

      在编译阶段,能调用哪些成员是由编译类型来决定的

    • 最终运行效果看子类(运行类型)的具体实现,即调用方法时,按照从子类开始查找方法(根据运行类型),然后调用,规则与方法调用规则一致。

  • 多态的向下转型

    1.语法:

    子类类型 引用名 = (子类类型) 父类引用;

    2.特点:

    • 只能强转父类的引用,不能强转父类的对象。
    • 要求父类的引用必须指向的是当前目标类型的对象。
    • 当向下转型后,可以调用子类类型中所有的成员。
  • 多态的注意事项和细节讨论:

    1.属性没有重写之说,属性的值看编译类型

    2.instanceof比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型。

  • 动态绑定机制
    1.当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
    2.当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。

多态的应用

多态数组

  • 数组的定义类型为父类类型,里面保存的实际元素类型为子类类型。
  • 使用向下转型。

多态参数

  • 方法定义的形参类型为父类,实参类型允许为子类。

Object类详解

equals方法

  • equals==的对比
    1.==比较运算符。既可以判断基本类型,又可以判断引用类型。如果判断基本类型,则判断的是是否相等;如果判断引用类型,则判断的是地址是否相等(即判定是不是同一个对象)。
    2.equalsObject类中的方法,只能判断引用类型。默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。

hashcode方法

  • 小结:
    1.提高具有哈希结构的容器的效率。
    2.两个引用,如果指向的是同一个对象,则哈希值一定相同;如果指向的是不同对象,则哈希值不相同。
    3.哈希值主要根据地址号来的,完全将哈希值等价于地址

toString方法

  • 基本介绍:
    默认返回全类名(包名+类名) + @ + 哈希值的十六进制,子类往往重写toString方法,用于返回对象的属性信息。
  • 重写toString方法打印对象或拼接对象时,都会自动调用对象的toString形式。
  • 当直接输出一个对象时,toString方法会被默认地调用。

finalize方法

  • 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作。
  • 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象。在销毁该对象前,会先调用finalize方法。
  • 垃圾回收机制的调用由系统来决定(即由自己的GC),也可以通过System.gc()主动触法垃圾回收机制。

断点调试debug

  • 在断点调试过程中,是运行状态,是以对象的运行类型来执行的。
  • 断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住。然后可以一步一步往下调试,调试过程中可以看各个变量的当前值,出错的话,调试到出错的代码行即显示错误,停下。进行分析从而找到这个bug。

断点调试快捷键

按键 内容
F7 跳入方法内
F8 逐行执行代码
Shift+F8 跳出方法
F9 resume,执行到下一个断点
  • 将光标放在某个变量上,可以看到最新的数据。
  • 可以在debug过程中动态的下断点。

Chapter 10

类变量/静态变量

类变量(静态变量/静态属性)是该类所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。

  • 类变量时对着类的加载而创建,所以即使没有创建对象实例也可以访问。
  • 类变量的生命周期是随类的加载开始,随着类消亡而销毁。

定义语法

(1)访问修饰符 static 数据类型 变量名; (推荐)
(2)static 访问修饰符 数据类型 变量名;

访问方法

(1)类名.类变量名 (推荐)
(2)对象名.类变量名

  • 类变量的访问必须遵循访问权限。

类方法/静态方法

定义语法

(1)访问修饰符 static 数据返回类型 方法名(){} (推荐)
(2)static 访问修饰符 数据返回类型 方法名(){}

调用

(1)类名.类方法名
(2)对象名.类方法名

使用场景

当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。

注意事项和细节讨论

  • 类方法和普通方法都是随着类的加载而加载,将结构信息储存在方法区。类方法中无this的参数,普通方法中隐含着this的参数。
  • 类方法可以通过类名调用,也可以通过对象名调用。
  • 普通方法和对象有关,需要通过对象名调用,不能通过类名调用。
  • 类方法中不允许使用和对象有关的关键字,比如thissuper,普通方法(成员方法)可以。
  • 类方法中只能访问静态变量和静态方法。
  • 普通成员方法既可以访问非静态变量(/方法),也可以访问静态变量(/方法)。

理解main方法语法

  • main方法是由虚拟机调用。
  • Java虚拟机需要调用类的mian()方法,所以该方法的访问权限必须是public。
  • Java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static。
  • 该方法接收String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。

特别提示

在main()方法中,我们可以直接调用main方法所在类的静态方法或静态属性。但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员。

代码块

基本介绍

代码化块又称为初始化块,属于类中的成员**(是类的一部分)。类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。
但代码块
没有方法名,没有返回,没有参数,只有方法体**,而且不用通过对象或类显示调用,而是在加载类或创建对象时隐式调用
代码块的调用优先于构造器。

基本语法

[修饰符]{
代码
};

注意:

  • “修饰符”可选,如果要写只能写static
  • 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的叫普通代码块/非静态代码块。
  • 逻辑语句可以为任何逻辑语句。
  • ;可以写上,也可以省略。

好处

  • 相当于另一种形式的构造器(对构造器的补充机制),可以做初始化的操作。
  • 如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性。

使用注意事项和细节讨论

  • static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行。并且只会执行一次。如果是普通代码块,每创建一个对象就执行。
  • 类什么时候被加载:
    • 创建对象实例时。
    • 创建子类对象实例,父类也会被加载。
    • 使用类的静态成员时(静态属性、静态方法)。
  • 普通的代码块在创建实例时,会被隐式的调用,被创建一次就被调用一次。如果只是使用类的静态成员时,普通代码块并不会执行。
  • 创建一个对象时,在一个类调用顺序是:
    1.调用静态代码块和静态属性初始化。(注意:静态代码块和静态属性初始化调用的优先级一样。如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用。
    2.调用普通代码块和普通属性的初始化。(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用。)
    3.调用构造方法。
  • 构造方法(构造器)的最前面其实隐含了super()和调用普通代码块。
  • 创建一个子类时(继承关系),他们的静态代码块、静待属性初始化、普通代码块、普通属性初始化、构造方法的调用顺序如下:
    1.父类的静态代码块和静态属性(优先级一样,按定义顺序执行)。
    2.子类的静态代码块和静态属性(优先级一样,按定义顺序执行)。
    3.父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)。
    4.父类的构造方法。
    5.子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)。
    6.子类的构造方法。
  • 静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。