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

数组长度
数组名.length
一维数组使用细节
数组创建后如果没有负值,那么会有默认值

增强for循环(补充)
语法 for(数据类型 变量名 : 数组名){}
注意:数组和变量要一个类型
例子(用在枚举上): for(Season season : values){}
运行模式:从values数组依次取一个Season类型的对象,把地址传递给season
方法(成员方法)
成员方法的定义:

成员方法细节
- 如果想接收多个返回值?返回数组。
- 方法不可以嵌套定义。
- 同一个类的方法可以直接调用 直接上例子: Class A { public void print(int n) { System.out.println("print()方法被调 用 n=" + n); } public void sayOK() { print(10);//在这里方法print就被调 用了 } }
- 跨类调用方法:需要通过对象名调用 public void m1(){//这个方法是A类中的 B b = new B(); b.hi();//这个hi是B类中的 }
- 在成员方法中引用到了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;
可变参数细节
-
可变参数可以和普通形参一起放在形参列表,但必须保证可变参数在最后
-
一个形参列表只能出现一个可变参数
-
可变参数进方法后是以类似数组的方式存在,读取其中数据也是用类似数组的方式读取
变量作用域(VarScope)
-
主要的变量是属性(成员变量)和局部变量。
-
局部变量一般指在成员方法中定义的变量
-
java中作用域的分类
- 全局变量:作用域为整个类体
- 局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中!
-
全局变量可以不赋值,直接使用,因为有默认值。
局部变量必须赋值后,才能使用,因为没有默认值。
-
全局变量可以被本类使用,或其他类使用(通过对象调用):
javapublic void test() { Person p1 = new Person(); System.out.println(p1.name);//jack }
javapublic void test2(Person p) { System.out.println(p.name);//jack }
但局部变量只能在本方法中使用
-
全局和局部变量可以重名,访问时遵循就近原则(比如在方法中定义了一个name,又在类中定义了一个name,此时在方法中使用到了name,那么这个name属于局部变量)
-
属性可以加修饰符,局部变量不能加修饰符
构造器
在先前创建人类的对象时,是先把一个对象创建好后,再给他的年龄和姓名赋值。
现在要求在创建人类对象是,就直接指定这个对象的年龄和姓名,该怎么做?这时就使用构造器。
基本语法
修饰符\] 方法名 (形参列表){ 方法体; } ### 老韩说明 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之间的一种访修饰符,一般称之为"**保护型** ",被其修饰的类,属性以及方法只能被该类本身的方法及[子类](https://so.csdn.net/so/search?q=%E5%AD%90%E7%B1%BB&spm=1001.2101.3001.7020)访问,即使**子类在不同的包中也可以访问.** * \*\*Default: \*\*即不加任何访问修饰符,通常称为"默认访问模式",即"**默认型** ",该模式下,**只允许在同一个包中进行访问.** * **Private:** java语言中[访问权限](https://so.csdn.net/so/search?q=%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90&spm=1001.2101.3001.7020)限制最窄的修饰符,一般称之为"**私有的** ",被其修饰的类,属性,以及方法只能被该类的对象访问,**其子类不能访问,更不允许跨包访问**. ### 访问修饰符图片助解  ## 封装(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. 枚举对象必须放在枚举类的行首 6. ```java enum Gender2{ /父类 Enum 的 toString BOY,GIRL; } Gender2 boy = Gender2.BOY://oK Gender2 boy2 = Gender2.BOY;//枚举类的对象是可以传递的 ``` 7. 父类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的介绍  *** ** * ** *** [\^](%E4%B8%8A%E9%9D%A2%E8%8E%B7%E5%8F%96%E5%88%B0%E7%9A%84%E6%97%A5%E6%9C%9F%E4%B9%9F%E5%8F%AF%E4%BB%A5%E8%A2%ABformat%E6%88%90%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E7%9A%84%E6%A0%BC%E5%BC%8F%EF%BC%8C%E4%BE%8B%E5%A6%82%EF%BC%9A): SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); *** ** * ** *** 1. 获取系统时间:java.util.Date [\^](%E4%B8%8A%E9%9D%A2%E8%8E%B7%E5%8F%96%E5%88%B0%E7%9A%84%E6%97%A5%E6%9C%9F%E4%B9%9F%E5%8F%AF%E4%BB%A5%E8%A2%ABformat%E6%88%90%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E7%9A%84%E6%A0%BC%E5%BC%8F%EF%BC%8C%E4%BE%8B%E5%A6%82%EF%BC%9A): 在Java中,获取当前日期最简单的方法之一就是直接实例化位于Java包java.util的Date类。 [\^](%E4%B8%8A%E9%9D%A2%E8%8E%B7%E5%8F%96%E5%88%B0%E7%9A%84%E6%97%A5%E6%9C%9F%E4%B9%9F%E5%8F%AF%E4%BB%A5%E8%A2%ABformat%E6%88%90%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E7%9A%84%E6%A0%BC%E5%BC%8F%EF%BC%8C%E4%BE%8B%E5%A6%82%EF%BC%9A): Date date = new Date(); // this object contains the current date value [↩︎](#↩︎)