Java学习笔记

数组

定义语法

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

遍历数组

数组长度

数组名.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^

  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 ↩︎
相关推荐
confiself13 分钟前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言
Wlq041518 分钟前
J2EE平台
java·java-ee
XiaoLeisj25 分钟前
【JavaEE初阶 — 多线程】Thread类的方法&线程生命周期
java·开发语言·java-ee
幼儿园老大*29 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
Selina K32 分钟前
shell脚本知识点记录
笔记·shell
豪宇刘40 分钟前
SpringBoot+Shiro权限管理
java·spring boot·spring
44 分钟前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
Elaine20239144 分钟前
02多线程基础知识
java·多线程
gorgor在码农1 小时前
Redis 热key总结
java·redis·热key
ctrey_1 小时前
2024-11-4 学习人工智能的Day21 openCV(3)
人工智能·opencv·学习