Java学习笔记

数组

定义语法

  1. int\[\] hens ={1,2,3,4,5},int\[\] arr = new int\[\] {1,2,3,4,5}(静态初始化)
  2. int\[\] hens =new int5;(这里是定义一个有5个位置的int类型数组)
  3. 先声明数组int\[\] hens; 再创建数组hens = new int5;

遍历数组

数组长度

数组名.length

一维数组使用细节

数组创建后如果没有负值,那么会有默认值

增强for循环(补充)

语法 for(数据类型 变量名 : 数组名){}

注意:数组和变量要一个类型

例子(用在枚举上): for(Season season : values){}

运行模式:从values数组依次取一个Season类型的对象,把地址传递给season

方法(成员方法)

成员方法的定义:

成员方法细节

  1. 如果想接收多个返回值?返回数组。
  2. 方法不可以嵌套定义。
  3. 同一个类的方法可以直接调用 直接上例子: Class A { public void print(int n) { System.out.println("print()方法被调 用 n=" + n); } public void sayOK() { print(10);//在这里方法print就被调 用了 } }
  4. 跨类调用方法:需要通过对象名调用 public void m1(){//这个方法是A类中的 B b = new B(); b.hi();//这个hi是B类中的 }
  5. 在成员方法中引用到了main方法中的数组或某个对象 然后再public void test200(Person p){ p = null;行参中的Person p是main方法中的一个对象,但是test200方法中的p与其不同,置空的只是test200中的p(也就是引用置空,实际引用地址是没有变化的)(这里也可以看出null这个代码并不是清空地址,只是取消引用),所以main方法中的p不发生任何变化。 }

方法递归调用

自己调 用自己:在tool方法里调用tool方法(有限套娃)(一定要有递归方法的出口,不然就是无限套娃了)

java 复制代码
public void test(int n){
    if (n > 2){//出口      
        test(n - 1);
    }
    System.out.println("n=" + n);
}//输出什么?2.3.4。

阶乘:

java 复制代码
public int factorial(int n){//在前面传入参量 n = 5    
    if (n == 1){      
        return 1;    
    }else{       
        return factorial(n - 1) * n;     
    } 
}//阶乘实际计算为1*2*3*4*5每次递归调用都要缩小范围,目标才能达到出口的条件。

方法重载

同一个方法名,有不同的形参

例如System.out.println();这个方法如果方法名不相同,那么就不叫重载。

返回值

return n1 > n2 ? n1 : n2;(这里的意思直接省略了if语句,而是用缩写公式完成了n1与n2的对比),这个语句也可以用在int a = n1 > n2 ? n1 : n2;

方法重载细节

public double max(double n1,double n2,double n3),在这个语句里如果前文给的形参是(double1,double2,int3)那么也是会匹配到上面这个方法,因为int类型可以转换为double。

但是max(double n1,double n2,double n3)与max(double n1,double n2,int n3)是方法重载

可变参数

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

可以通过可变参数实现。

基本语法:访问修饰符 返回类型 方法名(数据类型...形参名)//这里多个一个数据类型

public int sum(int... nums){}

还可以通过代码查询上面方法接受了几个参数 -> nums.length;

可变参数细节

  1. 可变参数可以和普通形参一起放在形参列表,但必须保证可变参数在最后

  2. 一个形参列表只能出现一个可变参数

  3. 可变参数进方法后是以类似数组的方式存在,读取其中数据也是用类似数组的方式读取

变量作用域(VarScope)

  1. 主要的变量是属性(成员变量)和局部变量。

  2. 局部变量一般指在成员方法中定义的变量

  3. java中作用域的分类

    • 全局变量:作用域为整个类体
    • 局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中!
  4. 全局变量可以不赋值,直接使用,因为有默认值。

    局部变量必须赋值后,才能使用,因为没有默认值。

  5. 全局变量可以被本类使用,或其他类使用(通过对象调用):

    java 复制代码
    public void test() {  
        Person p1 = new Person(); 
        System.out.println(p1.name);//jack   
    } 
    java 复制代码
    public void test2(Person p) {    
        System.out.println(p.name);//jack  
    }  

    但局部变量只能在本方法中使用

  6. 全局和局部变量可以重名,访问时遵循就近原则(比如在方法中定义了一个name,又在类中定义了一个name,此时在方法中使用到了name,那么这个name属于局部变量)

  7. 属性可以加修饰符,局部变量不能加修饰符

构造器

在先前创建人类的对象时,是先把一个对象创建好后,再给他的年龄和姓名赋值。

现在要求在创建人类对象是,就直接指定这个对象的年龄和姓名,该怎么做?这时就使用构造器。

基本语法

修饰符 方法名 (形参列表){ 方法体; }

老韩说明

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

  2. 构造器没有返回值

  3. 方法名和类名字必须一样

  4. 参数列表和成员方法一样的规则

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

  6. 在创建对象时,系统会自动的调用该类的构造器完成对对象的初始化

构造器细节:

  1. 构造器也可以重载,使用方法与方法重载一致

  2. 构造器是完成对象的初始化,不是创建对象 例子如下

    Person p1 = new Person("king", 40); //("king", 40)就是初始化内容

  3. 构造器要让系统自动调用,我们是无法调用的

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

即:Dog(){}(这点很重要)

构造器的复用

java 复制代码
public Employee(String job, double sal){ 
     this.job = job; 
     this.sal = sal;
 } 
public Employee(String name, char  gender, int age){  
    this.name = name; 
    this.gender = gender;  
    this.age = age; } 
public Employee(String job, double sal,String name, char gender, int age){ 
    this(name, gender, age);//使用到前面的构造器 this. job = job; this.sal = sal;
}

对象创建流程分析

看一个案例

java 复制代码
class Person{//类Person         
    int age = 90;      
    String name;  
    Person(String n; int a){//构造器  
        name = n;//给属性赋值       
        age = a;//...
    }
main(){
       Person p = new Person("小倩",20)
} 

流程分析:

  1. 先在方法区加载Person类
  2. 然后在堆内开空间,创建含age和 name变量的地址1(对象)并完成默认初 始化age = 0,name = null
  3. 然后再完成对age的赋值(90)
  4. 接着执行构造器 a.在常量池创建一个地址2并接收"小倩" b.让地址1中的name指向地址2 c.再把age重新赋值为20
  5. 最后才在栈中创建一个p指向地址1

反编译

javap

this关键字------对构造器形参名的优化

this.变量名;//访问this所在成员属性中的成员变量 ThisDetail

  • 访问成员方法的语法:this.方法名(参数 列表);

  • 访问构造器语法:this(参数列表); 注意只能在构造器中用且是第一条语句 (即只能在构造器中访问另一个)

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

同类不同方法相互调用

A. f1(); B. this.f1();

以上两种方法目前来说都能调用f1,但是具体区别在学到继承的时候

包的作用

  1. 区分相同名字的类

  2. 当类很多时可以很好的管理【API文档】

  3. 控制访问范围

包的基本语法

java 复制代码
package com.hspedu

package 关键字,表示打包

com.hspedu 表示包名

包的本质分析

就类似文件夹

命名规则

只能包含数字.字母.下划线.小圆点

但不能数字开头或者关键字、保留字

命名规范

一般是小写字母+小圆点

一般是com.公司名.项目名.业务模块名

常用的包

java.lang.* //基本包,默认引入

java.util.* //工具包,工具类(Scanner)

java.net.* //网络包,网络开发

java.awt.* //是做界面开发,GUI

IDEA

文件储存位置说明

  1. class文件编译后会储存在\out文件夹内

  2. .java文件在scr文件夹内

常用快捷键

  1. 删除当前行,默认ctrl + Y 自己配置ctrl+d

  2. 复制当前行粘贴到下一行,Ctrl+alt+向下光标

  3. 补全代码alt+/

  4. 导入当前行需要的类alt+enter

  5. 快速格式化代码ctrl+alt+L

  6. 运行程序 shift + F10(如果想快捷运行, 要先配置主类)

  7. 生成构造器alt + insert

  8. 查看一个类的层级关系 F4

  9. 定位方法源 ctrl+鼠标左键

  10. 自动分配变量名,在new Scanner()后面 加.var,然后回车

模板快捷键

  1. sout

  2. fori

  3. ...自己找模板 file->settings->editor->Live templates

IDEA查看jdk源码

老韩文件夹里有doc文档可看

访问修饰符

  • Public: java语言中访问限制最宽的修饰符,一般称之为"公共的 ",被其修饰的类,属性及方法,不仅可以跨类访问,而且允许跨包(package)访问
  • Protected: 介于public和private之间的一种访修饰符,一般称之为"保护型 ",被其修饰的类,属性以及方法只能被该类本身的方法及子类访问,即使子类在不同的包中也可以访问.
  • **Default: **即不加任何访问修饰符,通常称为"默认访问模式",即"默认型 ",该模式下,只允许在同一个包中进行访问.
  • Private: java语言中访问权限限制最窄的修饰符,一般称之为"私有的 ",被其修饰的类,属性,以及方法只能被该类的对象访问,其子类不能访问,更不允许跨包访问.

访问修饰符图片助解

封装(encapsulation)

封装的理解和好处

理解

封装就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(方法),才能对数据进行操作

好处

  • 隐藏实现细节

  • 可以对数据进行验证,保证安全合理

封装的实现步骤

  1. 将属性进行私有化private【不能直接修改属性】

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

    java 复制代码
    public void setXxx(类型 参数名){
         //加入数据验证的业务逻辑
        属性 = 参数名;
    }
  3. 提供一个公共的(public)get方法,用于获取属性的值

    java 复制代码
    public 数据类型 getXxx(){
         //权限判断,Xxx某个属性
         return Xxx;
    }

将构造器与封装结合

将set方法写在构造器内

继承

为什么要使用继承?

当多个类的属性和方法大量重复(需要提高代码复用性)

继承的基本语法

class 子类 extends 父类{ }(子类又叫派生类,父类叫基类,超类)

继承的细节问题

a. 子类不能直接引用父类的私有属性,要通过父类 公共的方法去访问

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

c. 创建子类对象时,不管使用子类的那个构造器,默认情况下总会去调用父类的无参,如果父类没有无参,则必须在子类的构造器中用 super去指定使用父类的某个构造器完成对父类的初始化工作 //super();

d. 如果希望指定去调用父类的某个构造器,则显示的调用一下super(参数列表)

e. super必须放在构造器第一行

f. super() 和 this()都只能放在构造器第一行,因此他俩不能共存在一个构造器

g. 不能滥用继承,子类和父类之间必须满足:子类 is a 父类

继承的内存布局

java 复制代码
public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();  
        System.out.println(son.name);  
        System.out.println(son.hobby);
    }
}
class GrandPa { //爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}
class Father extends GrandPa {//父类
    String name = "大头爸爸";
    private int age = 39;
    public int getAge() {
        return age;
    }
}
class Son extends Father{ //子类
    String name = "大头儿子";
}
//当Son son = new Son();这条语句执行时 会先在方法区内加载各个类,并且父类优先然后再堆中开空间从父类优先一个个创建属性并赋值(值来自方法区)

访问属性的原理

优先看子类中有没有需要的属性,如果有并且能访问,则返回信息;如果没有,就向上(父类)查找

super关键字

A. 访问父类的属性,但不能访问父类的private属性//super.属性名

B. 访问父类的方法,也是不能访问private //super.方法名(参数列表)

C. 访问父类的构造器,只能放在构造器的第一句,只能出现一句!只能在构造器!//super(参数列表)

一般只有子类中定义了与父类重名的属性、方法才会使用到super,如果上一个父类没有super指定的,则继续找父类的父类

super和this的冲突

在构造器中两者都只能写在第一行,所以构造器最多只能有他俩其一

方法重写

是什么?

简单来说子类中的一个方法与父类的某个方法的名称、返回类型、参数都一样,那么这个方法就称为覆盖(重写)了父类的方法

细节

a.返回类型可以不一样,但父类中的返回值得是子类中的返回值的父类,如父类是Object子类是String

b.子类方法不能缩小父类方法的访问权限

多态

为什么要使用多态?

譬如一个项目,有主人有动物,有食物又因为食物很多,喂食所需要的方法就 很多,不利于管理和维护(方法复用性不高,不利于管理与维护)

多态的具体体现

a. 方法的多态(方法重载/重写)

b. 对象的多态

​ 重要的几句话

​ (1) 一个对象的编译类型和运行类型可以不一致比如Animal animal = new Dog();//Dog是Animal的子类

​ (2) 编译类型在定义对象时,就确定了,不能改变

​ (3) 运行类型是可以变化的

​ (4) 编译类型看定义时 = 号的左边,运行类型看 =号的右边

​ (5) 编译类型与运行类型的区别

​ 当Dog是Animal的子类时

java 复制代码
      Animal animal = new Dog();
​      animal.cry();//这个时候cry运行的是Dog子类中的cry,因为运行时执行到该行时animal的运行类型是Dog,所以cry是Dog的cry
​      animal = new Cat();//这个时候运行类型又成了Cat

​ (6)把每个方法的形参都改为具体参数的父类,方法的复用性就极大地提高了

多态细节

a. 多态的前提:两个对象存在继承关系

b. 多态的向上转型

​ 本质:父类的引用指向了子类的对象

​ 语法:父类类型 引用名 = new 子类类型();

​ 特点:编译类型看左边,运行类型看右边。

​ 可以调用父类中的所有成员(遵守访问权限),但不能调用子类中特有成员;

​ //比如

​ Animal animal = new Cat();

​ animal.catchMouse();//这里会报错,无法调用Cat类的catchMouse方法

​ 最终运行效果看子类的具体体现

c. 多态的向下转型

​ 语法:子类类型 引用名 = (子类类型) 父类引用

​ Cat cat = (Cat) animal

​ 只能强转父类的引用,不能强转父类的对象

​ 要求父类的引用必须指向的是当前目标类型的对象

​ 可以调用子类类型中的所有成员就像是把向上转型给直接换成Cat cat = new cat();

属性重写问题

属性没有重写之说!属性的值看编译类型

instanceOf比较操作符

用于判断对象的运行类型是否为XX类型或XX类型的子类型

语法:aa instanceOf AA;//返回值为boolean

​ Sub s = new Sub();

Base b = s;//Base是Sub的父类

​ 此时 b == s的返回值是true

java动态绑定机制(非常非常重要)

a.当调用对象方法的时候,该方法会和该对象的内存地址/运行属性绑定

b.当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用

多态的应用(多态数组)

​ 创建了包含多个对象的数组,可以通过循环遍历

​ 特殊情况:

​ Person student = new Student();

​ //这里Student是Person的子类

​ //Student中有一个study成员方法

​ //但Person中没有这个方法,

//这时候使用student.study就会报错

​ //但是可以考虑用if配合instanceof来选择是否

//让student进行向下转型70.equals方法

equals方法

==和equals比对象比的是运行类型,(也就是判断引用地址是否相同)

区别:当equals比String类型时如果地址不相同,他会继续判断字符串长度是否相同,如果相同,会继续判断每个字符是否一一对应

equals只能判断引用类型

直接上代码:if(name.equals("丁真")){......}

重写equals方法

为什么要重写?

Object里面最原始的equals只是比较两个对象是否一样(如person1 != person2),不一样就直接返回false,但是有时候不同对象属性一样,就需要重写新的equals

新需求:equals比较的是两个有可能不是同一个的对象的属性是否一样,一样就返回true。

组织一下语言:

== :比较左右两个东西是不是一个东西

equals(Object):比较左右两个对象是不是一个对象

equals(重写):先比较是不是一个类型,再比较内容

hashCode

老韩的6个小结:

1)提高具有哈希结构的容器的效率

2)两个引用,如果指向的是同一个对象,则哈希值肯 定是一样的

3)两个引用,如果指向的是不同对象,则哈希值是不一样的

4)哈希值主要根据地址号来的,不能完全将哈希值等价于地址.

5)案例演示HashCode_.java:obj.hashuCode()

A aa = new A();

A aa2 = new A();

aa3 = aa;

6)后面在集合中hashCode如果需要的话,也会重写

toString方法

默认返回: 全类名 + @ + 哈希值的十六进制

子类往往重写toString方法,用于返回对象的属性信息

调用语法:

1.对象名.toString();

2.对象名;//真就这么简单

重写toString方法

使用快捷键即可alt + insert(IDEA)

finalize

当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法

解释:

  1. 当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作。

  2. 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法

  3. 垃圾回收机制的调用,是由系统来决定(GC回收算法),也可以通过System.gc()主动触发垃圾回收机制(不一定能成功触发)

  4. Object类的finalize方法是空的,什么都没干

ps:实际开发中一般不会用...应付面试官

零钱通

化繁为简:

  1. 先完成显示菜单,并可以选择菜单,给出相应提示

  2. 完成零钱通明细

    老韩思路:

    1. 可以把收益入账和消费,保存到数组;
    2. 可以使用对象
    3. 简单的话可以使用String拼接

    System.out.println("1 零钱通明细"); System.out.println("------------------------------------零钱通明细------------------------------------");

  3. 完成收益入账 完成功能驱动程序员增加新的变量和代码

    老韩思路:定义新的变量

    java 复制代码
    double money = 0;
    double balance;

    //需要获取系统时间[1](#1)

  4. 完成消费信息

    定义新变量place//消费地点

  5. 完成退出提示

至此,以上是面向过程的方法完成零钱通的流程。

Chapter08Homeworks

断点调试(IEDA)

当程序运行到断点处时,程序暂停,程序员可以开始一步步往下运行

快捷键:

F7:跳入方法内

F8:逐行执行代码

shift + F8:跳出方法

F9:执行到下一个断点//可以在dubug过程中动态的下断点

进入Jdk源码有问题?

解决方法1:

使用force step into:快捷键 alt + shift + F7

解决方法2:

配置一下(方法在330集)

chapter09

先停在第342集,转枚举

枚举

枚举(enumeration)的引出

现在有个需求:创建季节(Season)对象,请设计并完成

java 复制代码
//思路清晰,先建个类,给属性1.name 2.desc(描述)
class Season{
    private String name;
    private String desc;
    //构造器
    //_get()
}
public class Main{
	public static void main(String args[]){
    	Season summer = new Season("夏天","炎热");
    	Season spring = new Season("春天","温暖");
    	Season autumn = new Season("秋天","凉爽");
    	Season winter = new Season("冬天","寒冷");
    	Season other = new Season("红天","666");
	}
}

出现问题:因为对于季节而已,他的对象(具体值),是固定的四个,不会有更多

​ 按上面的设计思路,不能体现季节是固定的四个对象

​ 甚至可以通过set方法将summer.name改为别的字符串

​ 因此,这样的设计不好......==>枚举的需求诞生【枚:一个一个 举:列举;即把具体的对象一个一个列举出来】

自定义枚举类

java 复制代码
class Season{
    private String name;
    private String desc;
	//1.将构造器私有化,目的防止直接new
    //2.去掉setXxx的相关方法,只能读,不能修改
    //3.在Season内部,直接创建固定的对象
    public static final Season SPRING = new Season("春天","温暖");
    public static final Season SUMMER = new Season("夏天","炎热");
    public static final Season AUTUMN = new Season("秋天","凉爽");
    public static final Season WIMTER = new Season("冬天","寒冷");
    
    private Season(String name, String desc) {
		super();
		this.name = name;
		this.desc = desc;
	}
	public String getName() {
		return name;
	}
	public String getDesc() {
		return desc;
	}
	@Override
	public String toString() {
		return "Season [name=" + name + ", desc=" + desc + "]";
	}
    
    
}

public class Enumeration02 {
	public static void main(String args[]) {
		System.out.println(Season.SPRING);
	}
}

写完发现,代码很长,很费事,那么就需要引出:

使用enum关键字实现枚举类

  1. 将定义常量对象放在最前面
  2. 使用关键字 enum 替代 class
  3. public static final Season SPRING = new Season("春天","温暖") 直接使用SPRING("春天","温暖")来替代
  4. 如果有多个对象,使用","间隔 :SPRING("春天","温暖"),SUMMER("夏天","炎热"),......;

enum关键字实现枚举注意事项

  1. 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类[如何证],老师使用 javap 工具来演示

  2. 传统的 public static final Season2 SPRING = new Season2("春天","温暖");简化成 SPRING ("春天","温暖"),这里必须知道,它调用的是哪个构造器.

  3. 如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略

  4. 当有多个枚举对象时,使用,间隔,最后有一个分号结尾

  5. 枚举对象必须放在枚举类的行首

java 复制代码
enum Gender2{ /父类 Enum 的 toString 
    BOY,GIRL; 
 }
Gender2 boy = Gender2.BOY://oK 
Gender2 boy2 = Gender2.BOY;//枚举类的对象是可以传递的
  1. 父类Enum的toString方法返回的是枚举对象的对象名,比如上面的代码,boy.toString()就是返回BOY

enum常用方法说明

valueOf 方法说明

enum细节

  1. 使用enum关键字后,就不能再继承其他类了,因为enum会隐式继承Enum,而Java是单继承机制

  2. 枚举类和普通类一样,可以实现接口,如下形式

    enum 类名 implements 接口1,接口2{}

注解( Annotation )

注解的理解

  1. 注解( Annotation )也被称为元数据( Metadata ),类、方法、属性、构造器、局部变量等数据信息。
  2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
  3. 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等。

基本的Annotation的介绍


^: SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");


  1. 获取系统时间:java.util.Date
    ^: 在Java中,获取当前日期最简单的方法之一就是直接实例化位于Java包java.util的Date类。
    ^: Date date = new Date(); // this object contains the current date value ↩︎
相关推荐
腻害兔5 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社6 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
克里斯蒂亚诺更新6 小时前
ruoyi角色权限的对应关系
笔记
萧瑟余晖7 小时前
JDK 26 新特性详解
java·开发语言
马优晨7 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
a1117769 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao9 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
维天说10 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
破碎的南瓜10 小时前
sqli--sql注入过关笔记(1,2,3,4,5,9)
数据库·笔记·sql
Zane199411 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端