
本文共 38834 字,大约阅读时间需要 129 分钟。
目录
Java下载:https://www.oracle.com/java/technologies/javase-jdk14-downloads.html
C:\Users\Administrator>cd C:\Users\Administrator\Desktop\Java\Project #进入新建的程序文件夹
C:\Users\Administrator\Desktop\Java\Project>javac HelloWorld.java #编译 C:\Users\Administrator\Desktop\Java\Project>java HelloWorld #运行 Hello,World! C:\Users\Administrator\Desktop\Java\Project>
public class [文件名,类名称] { public static void main(String[] args){ #程序执行起点 main System.out.println("Hello,World!"); #打印输出 }}
基础
关键字:1、小写;2、编写变色。
标识符:字母、数字、$、_。常量:- 字符串常量("abc");
- 整型常量;
- 浮点数常量;
- 字符常量('a'。不能为空,只能有一个字符);
- 布尔常量(true、false);
- 空常量(null。不能直接用来打印)。
变量:数据类型 变量名;
基本数据类型:- 整数型-byte short int long; #long后要加 L
- 浮点型-float double; #float后要加 F
- 字符型-char;
- 布尔型-boolean.
引用数据类型:字符串、数组、接口、lambda
数据类型装换:
- 自动类型转换(隐式):数据范围从小到大
- 强制类型装换(显式):(范围小的类型)范围大的数据
---精度损失、数据溢出
---byte、short、char在运算时,首先转化成int类型,再计算 例如:byte num1 = 40; byte num2 = 50; int result = num1 + num2; # byte + byte ---> int + int ---> int ---boolean不能进行数据类型转换 ---byte、short、char右侧赋值数值没有超过范围,编译器会补上(byte)、(short)、(char) 例如:byte num1 = /*(byte)*/ 30; char zifu = /*(char)*/ 65; ASCII编码表:48 -> '0' 65 -> 'A' 97 -> 'a' 例如:char zifu1 = 'A';System.out.println(zifu1 + 0);or:int num = zifu1;System.out.println(num);
算术运算符:四则运算符(+、-、*、/)、取模(%)、自增自减运算符(++、--)
1、两个不同类型的数据,结果是数据类型范围大的那种 例如:int x = 10;double result = x + 2.5; # int + double ---> double + double ---> double System.out.println(result);
2、对于字符串String(首字母大写,不是关键字)来说,加号表示连接
例如:String str1 = "Hello";System.out.println(str1); #cmd打印:HelloSystem.out.println("Hello" + "World"); #cmd打印:HelloWorldSystem.out.println(str + 20); #cmd打印:Hello20#String + int ---> StringSystem.out.println(str + 20 + 30); #cmd打印:Hello2030 优先级#(String + int) + int ---> String + int ---> String
赋值运算符:基本赋值运算符 =、符合赋值运算符 +=、-=、*=、/=、%=
比较运算符:==、<、>、<=、>=、!=逻辑运算符:&&、||、!三元运算符:数据类型 变量名称 = 条件判断 ? 表达式A : 表达式B;方法定义:(类似于C语言的函数)
public static void [方法名称](){ 方法体;}
方法调用:方法名称();
顺序结构: 判断结构:
1、 if(关系表达式){ 语句体; }2、 if(关系表达式){ 语句体1; } else{ 语句体2; }3、 if(判断条件1){ 语句体1; } else if(判断条件2){ 语句体2; } . . . else{ 语句体n; }
选择结构:[表达式:byte、short、char、int、String、enum]
switch(表达式){ case 常量值1: 语句体1; break; case 常量值2: 语句体2; break; . . . default: 语句体n+1; break;}
循环结构:
基本组成部分:初始化语句、条件判断、循环体、步进语句。 for循环:for(初始化表达式;布尔表达式;步进表达式){ 循环体;}
while循环:
1、 while(条件判断){ 循环体; } 2、 初始化语句; while(条件判断){ 循环体; 步进语句; }
do-while循环:
1、do{ 循环体; }while(条件判断); 2、 初始化语句; do{ 循环体; 步进语句; }while(条件判断);
循环控制:break、continue
循环嵌套:面向对象
IDE:集成开发环境----Eclipse
IDEA:https://pan.baidu.com/s/1HZ1_uyM1HCVxmMytvnWfDQ?提取码:en46方法:参数、返回值修饰符 返回值类型 方法名称(参数类型 参数名称, ...){ 方法体; return 返回值;}
方法的三种调用格式:
- 单独调用:方法名称(参数);
- 打印调用:System.out.println(方法名称(参数));
- 赋值调用:数据类型 变量名称 = 方法名称(参数);
返回值类型为void不能使用打印调用和赋值调用。
方法注意事项:
- 1、方法不能嵌套;
- 2、方法定义前后顺序无所谓;
- 3、方法定义后要调用;
- 4、方法有返回值必须有return且必须和方法的类型一致;
- 5、方法void没有返回值不写return或者[return;];
- 6、一个方法可以有多个return但是同时只能执行一个;
方法重载:overlord
方法名称一样,但是参数列表不一样(参数类型:个数不同,类型不同,多类型顺序不同) 与参数的名称无关、与方法的返回值类型无关数组:引用数据类型、多个数据的类型必须统一、长度在运行期间不可更改
数组初始化: 1)动态初始化:(指定长度) ---> 它的每一个值 整数为0 浮点数为0.0 字符类型'\u0000' 布尔类型false 引用类型null 数据类型[] 数组名称 = new 数据类型[数组长度]; 拆分两步: 数据类型[] 数组名称; 数组名称 = new 数据类型[数组长度]; 2)静态初始化:(指定内容) 数据类型[] 数组名称 = new 数据类型[]{元素1, 元素2...}; 拆分两步: 数据类型[] 数组名称; 数组名称 = new 数据类型[]{元素1, 元素2...}; 数据类型[] 数组名称 = {元素1, 元素2...}; 不可拆分两步获取数组元素:
System.out.println(数组名称); ---> 打印的是数组对应内存地址的哈希值 数组名称[索引值]; 数组的长度:数组名称.length面向过程:
面向对象: [封装、继承、多态] JDK提供一个Array类:import java.util.Arrays;System.out.println(Arrays.toString(array));
类:一组相关属性和行为的集合。 ---> 抽象的
对象: ---> 具体的类是对象的模板,对象是类的实体。public class 类名称{ 成员变量; 成员方法; ---> 定义时没有static}
一个类不能直接使用,要创建一个对象才可以使用。
1、导包 import 包名称.类名称; 与类在同一个包,可以省略导包语句不写。2、创建 类名称 对象名 = new 类名称(); Student stu = new Student();3、使用 使用成员变量:对象名.成员变量名 使用成员方法:对象名.成员方法名(参数)局部变量与成员变量的区别:
1、定义的位置不一样。 局部变量:在方法内部 成员变量:在方法外部,直接写在类当中 2、作用范围不一样。 局部变量:只有方法当中可以使用,出了方法就不可以用了 成员变量:整个类全部都可以通用 3、默认值不一样。 局部变量:没有默认值,如果想要使用,必须手动进行赋值 成员变量:如果没有赋值,会有默认值,规则与数组一样 4、内存的位置不一样。 局部变量:位置位于栈 成员变量:位于堆内存 5、生命周期不一样。 局部变量:随着方法进栈而产生,随着方法出栈而消失 成员变量:随着对象被创建而产生(new),随着对象被垃圾回收而消失面向对象三大特性之封装性: 封装性体现: 1、方法就是一种封装; 2、关键字private也是一种封装。 --->本类可以直接访问,超出本类以外就不在直接访问private int age; //private关键字,此类以外不能用 //这个成员方法,专门用于向age设置数据public void setAge(int num){ if(num > 0 && num < 100){ age = num; }else{ System.out.println("数据不合理!"); }} //这个成员方法,专门用于获取age的数据public int getAge(){ return age;}
对于boolean类型,setXxx不变,getXxx改为isXxx。
this关键字:
- 当方法的局部变量与类的成员变量重名时,优先使用局部变量
- 想用本类的成员变量:this.成员变量名
- 谁调用方法,谁就是this
构造方法:专门用来创建对象的方法,通过new创建对象时就是在调用构造方法。
public 类名称(参数类型 参数名称){ 方法体}
注意:
- 1、构造方法的名称必须和类名称完全一样
- 2、构造方法不写返回值类型,连void也不写
- 3、构造方法不能return一个返回值
- 4、如果没有编写任何构造方法,编译器会默认赠送一个构造方法,没有参数,方法体什么也不做
- 5、一旦编写了至少一个构造方法,编译器将不再赠送
- 6、构造方法也是可以重载的
Student类 private String name; private int age; public Student(){ ---> 无参构造方法 } public Student(String name, int age){ ---> 全参构造方法 this.name = name; this.age = age; } 加上get(name/age)、set(name/age)useStudent文件 Student stu1 = new Student(); Student stu2 = new Student("Jiao", 23); System.out.println("Name:" + stu2.getName() + ",Age:" + stu2.getAge());
定义一个标准的类:[Java Bean]
- 1、所有的成员变量都要加private关键字修饰
- 2、为每一个成员变量编写一对setter、getter方法
- 3、编写一个无参数的构造方法
- 4、编写一个全参数的构造方法
API:
Scanner类:键盘输入import java.util.Scanner; //System.in表示从键盘输入Scanner sc = new Scanner(System.in);//获取键盘int数字, int num = sc.nextInt();//获取键盘String字符串, String str = sc.next();int num = sc.nextInt();System.out.println("输入的数字是:" + num); String str = sc.next();System.out.println("输入的字符串是:" + str);
匿名对象: 传统:Student stu1 = new Student();
- 只有右边的对象,没有左边的名字和赋值语句
- 只能使用唯一的一次,下次再用不得不再创建一个新对象。
int num = new Scanner(System.in).nextInt();
使用匿名对象传参:
main中 methodParam(new Scanner(System.in));methodParam中 public static void methodParam(Scanner sc){ int num = sc.nextInt(); System.out.println("输入的数字是:" + num); }
使用匿名对象返回值:
main中 Scanner sc = methodReturn(); int num = sc.nextInt(); System.out.println("输入的数字是:" + num);methodParam中 public static Scanner methodReturn(){ return new Scanner(System.in); }
Random类:生成随机数
import java.util.Random; Random r = new Random(); //获取一个随机的int数字(有正负),int num = r.nextInt();int num1 = r.nextInt();System.out.println("随机数字是:" + num1);//获取一个随机的int数字(参数代表范围,左闭右开),int num = r.nextInt(3); -> [0,3)int num2 = r.nextInt(5);System.out.println("随机数字是:" + num2);
对象数组:
Student[] array = new Student[3];Student one = new Student("JiaoLiang",23);Student two = new Student("ZhangXuan",22);Student three = new Student("Hello",18); array[0] = one;array[1] = two;array[2] = three;System.out.println(array[1].getName());
集合类(ArrayList):长度可变
import java.util.ArrayList;- 对于ArrayList后面有一个<E> 表示泛型:装在集合当中的所有元素,全都是统一的什么类型
- 泛型只能是引用类型,不是基本类型
- 创建了一个ArrayList集合,集合的名称是list,里面全部装的是String字符串型的数据
ArrayList<String> list = new ArrayList<>();
ArrayList的常用方法
- 1、public boolean add(E e); 向集合中添加元素,参数的类型与泛型类似,返回值代表是否添加成功
- 2、public E get(int index); 从集合中获取元素,参数是索引编号,返回值就是对应位置的元素
- 3、public E remove(int index); 从集合中删除元素,参数是索引编号,返回值就是被删除的元素
- 4、public int size(); 获取集合的尺寸长度,返回值就是集合中包含的元素个数
//向集合当中添加一些数据,用add方法list.add("赵丽颖");list.add("迪丽热巴");list.add("高圆圆");list.add("古力娜扎");System.out.println(list);//从集合中获取元素,用get方法String name = list.get(2);System.out.println("索引值[2]是:" + name);//从集合中删除元素,用remove方法String whoRemove = list.remove(1);System.out.println(whoRemove);System.out.println(list);//获取集合的长度(元素的个数),用size方法int size = list.size();System.out.println(size);//遍历for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i));}
如果希望集合ArrayList当中存储基本类型数据,必须使用基本类型对应的 包装类
基本类型 包装类(引用类型,包装类都位于java.long包下)byte Byteshort Shortint Integerlong Longfloat Floatdouble Doublechar Characterboolean Boolean
ArrayList<Integer> list1 = new ArrayList<>();
字符串:常量,永远不可变。== char[]型字符数组,低层是byte[]字节数组
创建方式: 1、三种构造方法:- public String(); 创建一个空白字符串,不含有任何内容。
- public String(char[] array); 根据字符数组的内容,来创建对应的字符串。
- public String(byte[] array); 根据字节数组的内容,来创建对应的字符串。
//空参构造String str1 = new String();System.out.println("str1的字符串是:" + str1);//字符数组构造char[] charArray = { 'A', 'B', 'C'};String str2 = new String(charArray);System.out.println("str2的字符串是:" + str2);//字节数组构造byte[] byteArray = {97 ,98, 99};String str3 = new String(byteArray);System.out.println("str3的字符串是:" + str3);
2、一种直接创建:
字符串的常量池:程序中直接写上双引号的字符串,就在字符串常量池中。- 基本型 ==比较 数值比较
- 引用型 ==比较 地址值比较
1、public boolean equals(Object obj); 参数可以是任何对象,只有参数是一个字符串内容相同才会返回true。
1、任何对象都可以用Object进行接收。 2、equals方法具有对称性,也就是a.equals(b)与b.equals(a)一样。 3、如果一个常量一个变量,推荐把常量字符串写在最前面:"abc".equals(str);2、public boolean equalsIgnoreCase(String str); 忽略大小写,进行内容比较。字符串的获取相关方法:- public int length(); 获取字符串中含有字符个数,拿到字符串的长度。
- public String concat(String str); 将当前字符串和参数字符串拼接成为返回值新的字符串。
- public char charat(int index); 获取指定索引位置的单个字符。
- public int indexOf(String str); 查找参数字符串在本字符串中首次出现的索引位置,若没有返回-1值。
字符串的截取方法:
- public String substring(int index); 截取从参数位置到字符串末尾,返回新字符串。
- public String substring(int begin, int end); 截取从begin开始到end结束,中间的字符串。[begin, end)
字符串的转换方法:
- public char[] toCharArray(); 将当前字符串拆分为字符数组作为返回值。
- public byte[] getBytes(); 获得当前字符串低层的字节数组。
- public String[] replace(CharSequence oldString, CharSequence newString);
将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。
CharSequence接口:可以接收字符串类型字符串的分割方法:- public String[] spilt(String regex); 按照参数的规则,将字符串切分成为若干部分。
regex 是 正则表达式 按照"."分割,要写成"\\."
静态static: 1)一旦用了static关键字,那么这样的内容就不属于对象自己,而是属于类。凡是本类的对象,都共享一份。 static String room; 2)一旦使用static修饰成员方法,那么就成了静态方法。//静态方法obj.methodStatic(); //不推荐这样做--->javac后会变成“类名称.静态方法名”MyClass.methodStatic(); //推荐
如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它。
//成员方法MyClass obj = new MyClass();obj.method();
无论成员变量,还是成员方法,如果有static,都推荐用类名称调用。
静态变量:类名称.静态变量 静态方法:类名称.静态方法()静态不能直接访问非静态。 原因:在内存中先有静态内容,后有非静态内容。静态方法不能使用this关键字。 原因:this表示当前对象,通过谁调用方法,谁就是当前对象。静态代码块:
格式:public class 类名称{ static { 静态代码块的内容; }}
当第一次用到本类时,静态代码块执行位唯一一次。 静态的内容优先于非静态的内容。 静态的代码块的用图:用来一次性的对静态成员变量进行赋值。
常用的工具类:
1)Array:java.util.Arrays 与数组相关的工具类,提供大量的静态方法。- public static String toString(数组); 将参数数组变成字符串。
- public static void sort(数组); 默认升序对数组元素进行排序
注意:数值---按照升序
字符串---字母升序 自定义类型---它需要有Comparable或Comparator接口支持2)Math:java.lang.Math 与数学相关的工具类,提供大量的静态方法。
- public static double abs(double num); 获取绝对值
- public static double ceil(double num); 向上取整
- public static double floor(double num); 向下取整
- public static long round(double num); 四舍五入
3)Math.PI 近似pai
继承:继承是多态的前提。 继承主要解决的就是:共性抽取。特点:子类可以拥有父类的 “内容”;子类可以拥有父类的 “新内容”定义父类格式:public class 父类名称(){ ...}定义子类格式:public class 子类名称 extends 父类名称(){ ...}
在父子类继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
1)直接:通过子类对象访问成员变量。 等号左边是谁,就优先用谁,没有则向上找。 2)间接:通过成员方法访问成员变量。 该方法属于谁,就优先用谁,没有则向上找。区分子类三种方法重名的三种变量:
- 局部变量: 直接写成员变量名
- 本类的成员变量: this.成员变量名
- 父类的成员变量: super.成员变量名
成员方法的访问特点:
在父子类继承关系中,创建子类对象,访问成员方法的规则: 创建的对象是谁,就优先用谁,如果没有则向上找。 注意:无论成员方法还是成员变量,如果没有就是向上找,绝对不会向下找子类的。方法的覆盖重写(Override)-覆盖-复写:方法名称一样,参数列表也一样。
重载(Overload):方法名称一样,参数列表不一样。特点:创建的是子类对象,则优先用子类方法。注意:1、方法名称与参数列表都相同。
@override:写在方法前面,用来检测是不是有效的正确覆盖重写。--->没写也可以 2、子类方法的返回值必须小于等于父类方法的返回值范围。 前提:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String类就是Object的子类。 (方法void ---> 改为:Object与String) 3、子类方法的权限必须大于等于父类方法的权限修饰符。 扩展:public > protected > (default) > private (default)不是关键字default,而是什么都不写,留空。继承中构造方法的访问特点:
- 1、子类构造方法当中有一个默认隐含的“super();”调用,所以一定是先调用的父类构造,后执行的子类构造。
- 2、子类构造可以通过super关键字来调用父类重载构造。
- 3、super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
注意:子类必须调用父类的构造方法,不写则赠送 super();
写了则用写指定的super调用,super只能有一个,还必须是第一个。super关键字的三种用法总结:- 1、在子类的成员方法中,访问父类的成员变量。 super.成员变量
- 2、在子类的成员方法中,访问父类的成员方法。 super.成员方法
- 3、在子类的构造方法中,访问父类的构造方法。 super(); 或 super(参数);
this关键字的三种用法总结:
- 1、在本类的成员方法中,访问本类的成员变量。
- 2、在本类的成员方法中,访问本类的成员变量。
- 3、在本类的构造方法中,访问本类的另一个构造方法。 本类无参构造调用本类的有参构造
必须是构造方法的第一个语句,唯一一个。
super和this两种构造不能同时使用。java继承的三个特点:
1、Java语言是单继承的:一个类的直接父类只能有唯一一个。 2、Java语言可以多级继承: class A{} class B extends A{} class C extends B{} 3、一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类 class A{} class B extends A{} class C extends A{}抽象:如果父类当中的方法不确定如何进行{}方法体实现,那么就是一个抽象方法。
抽象方法:加上abstract关键字,然后去掉大括号,直接分号结束。 抽象类:抽象方法所在的类,必须是抽象类才行,在class之前加上abstract即可。使用步骤:
1、不能直接创建new抽象类对象。 2、必须用一个子类来继承抽象父类。 3、子类必须覆盖重写抽象父类当中的所有的抽象方法。 覆盖重写(实现):去掉抽象方法的abstract关键字,然后补上方法体大括号。 4、创建子类对象进行使用。注意事项: 1、抽象类不能创建对象。 2、抽象类可以有构造方法,供子类创建对象时,初始化父类成员使用。 3、抽象类中,不一定包含抽象方法,但是抽象方法的类必须是抽象类。 4、抽象的类的子类,必须重写抽象父类中所有的抽象方法,不然会报错。 除非该子类也是抽象类。接口:就是一种公共的规范标准。是引用数据类型,最重要的就是抽象方法。
定义格式:public interface 接口名称{ ...}
class换成了interface之后,编译生成的字节码文件后还是.java -> .class
- java7: 1、常量 2、抽象方法
- java8: 3、默认方法 4、静态方法
- java9: 5、私有方法
接口的抽象方法:
public abstract 返回值类型 方法名称(参数列表);public abstract void methodAbs();
注意:1、修饰符必须是两个固定的关键字,public abstract
2、修饰符可以选择性的省略 3、方法的三要素可以随意定义 使用:1、接口不能直接使用,必须有一个“实现体”来“实现”该接口。 public class 实现类名称 implement 接口名称{ ... } 2、接口的实现类必须覆盖重写 接口中的所有的抽象方法。 实现:去掉abstract关键字,加上方法体大括号。 3、创建实现类的对象,进行使用。 注意:如果实现类并没有覆盖重写接口中的所有的抽象方法, 那么这个实现类自己就必须是抽象类。接口的默认方法: 可以解决接口的升级问题。 public default 返回值类型 方法名称(参数列表){ 方法体 } 1、接口的默认方法,可以通过接口实现类对象,直接调用。 2、接口的默认方法,可以被接口实现类进行覆盖重写。接口的静态方法: public static 返回值类型 方法名称(参数列表){ 方法体 } 提示:就是把abstract或者default换成static即可,带上方法体。 注意:不能通过接口实现类的对象直接调用接口的静态方法。 正确用法:通过接口名称直接调用静态方法。接口的私有方法:
问题:需要抽取一个共有方法,用来解决默认方法之间重复代码的问题 但是这个共有方法不能在实现类中使用,应该是私有化的。 1、普通私有方法:解决多个默认方法之间重复代码问题 格式:private 返回值类型 方法名称(参数列表){ 方法体 } 2、静态私有方法:解决多个静态方法之间重复代码问题 格式:private static 返回值类型 方法名称(参数列表){ 方法体 }接口的常量: 接口中可以定义“成员变量”,但是必须是public static final三个关键字进行修饰。 从效果上看,这就是接口的“常量” 格式: public static final 数据类型 常量名称 = 数据值; 注意: 一旦是使用final关键字,说明不可修改。 接口中的常量,必须进行赋值,不能不赋值。 接口中常量的名称,使用完全大写的字母,用下划线分割。接口注意事项:
1、接口是没有静态代码块与构造方法的 2、一个类的直接父类是唯一的,但是一个类可以同时实现多个接口 格式: public class MyInterfaceImpl implement MyInterfaceA,MyInterfaceB{ //覆盖重写所有抽象方法 } 3、如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。 4、如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。 5、如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的 默认方法进行覆盖重写。 6、一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先使用父类当中的方法。类与接口: 1、类与类之间是单继承的,直接父类只有一个。 2、类与接口之间是多实现的。一个类可以实现多个接口。 3、接口与接口之间是多继承的。注意事项: 1、多个父接口当中的抽象方法如果重复,没关系。 2、多个父接口当中的默认方法如果重复,有那么子接口必须进行默认方法的覆盖重写, 而且带着default关键字。面向对象的多态(polymorphism)
代码当中体现的多态性,其实就是一句话:父类引用指向子类对象 格式; 父类名称 对象名 = new 子类名称(); 接口名称 对象名 = new 实现类名称(); 多态中成员变量的使用特点: 1、直接通过对象名称访问成员变量,看等号左边是谁,没有则向上找。 2、间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上找。 多态中成员方法的使用特点: 看new的是谁,就优先用谁,没有则向上找。 成员变量口诀:编译看左,运行看左。 成员方法口诀:编译看左,运行看右。 使用多态的好处: 无论右边new的时候换的是哪个子类对象,等号左边的调用方法都不会改变。对象的向上转型:
就是多态的写法: 格式:父类名称 对象名 = new 子类名称(); 右侧创建一个子类对象,把它当做父类来看待使用。 向上转型一定是安全的。类似于自动转型:double num = 10; int --> double。对象的向下转型:
调用子类特有方法。 多态定义后,对象类特有的方法 不能在Main中直接使用 解决方法:用对象的向下转型“还原” 格式:子类名称 对象名 = (子类名称)父类对象; 含义:就是将父类对象,还原为本来的子类对象。instanceof关键字:判断父类引用的对象,本来是什么子类。
格式:对象 instanceof 类型 这将会得到一个boolean值的结果,也就是判断前面的对象能不能当做后面类型的实例。 fina关键字:最终的、不可改变的 常见四种用法: 1、可以用来修饰一个类 格式: public final class 类名称{ ... } 含义:当前这个类不能有任何的子类。(太监类) 不能用一个final类作为父类。 注意:一个类如果是final的,那么其中的成员方法都无法进行覆盖重写。(没儿子) 2、可以用来修饰一个方法 当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能覆盖重写。 格式: public final 返回值类型 方法名称(参数列表){ ... } 注意事项: 对于类与方法来说,abstract与fianl不能同时使用,因为矛盾。 3、还可以用来修饰一个局部变量 一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。(一次赋值,终身不变) 例如:final int num; num = 10; //正确写法,只要保证一次赋值即可 对于基本类型来说,不可改变就是变量的数据不可改变 对于引用类型来说,不可改变就是变量中的地址值不可改变 4、还可以用来修饰一个成员变量 对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变的。 A、对于成员变量具有默认值(0,Null),所以用了final之后必须手动赋值,不在给默认值了。 B、对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值,二者选其一。 C、必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。四种权限修饰符:
public > protected > (default) > private 同一个类 YES YES YES YES 同一个包 YES YES YES NO new 另一个类名称.成员变量 不同包子类 YES YES NO NO 不同包非子类 YES NO NO NO内部类:
如果一个事物的内部包含另外一个事物,那么这就是一个类内部包含另一个类。 分类: 1、成员内部类 格式: 修饰符 class 外部类名称{ 修饰符 class 内部类名称{ ... } ... } 注意:内用外,随意访问;外用内,需要借助内部类对象。 使用: A、间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。 B、直接方式: 类名称 对象名 = new 类名称(); 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称(); 如果出现重名现象,那么格式是: 外部类名称.this.外部类成员变; 2、局部内部类(包含匿名内部类) 如果一个类定义在一个方法的内部,那么这就是一个局部内部类。 “局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。 定义格式: 修饰符 class 外部类名称{ 修饰符 返回值类型 外部类方法名称(参数列表){ class 局部内部类名称{ ... } } ... } 注意:局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效的final】 定义一个类的权限修饰符: 1、外部类:public / (default) 2、成员内部类:public / protected /(default)/ private 3、局部内部类:什么都不写匿名内部类:(重要)
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次, 那么这种情况下就可以省略掉该类的定义,而改为使用【匿名局部类】 定义格式: 接口名称 对象名 = new 接口名称{ //覆盖重写所有的抽象方法 }; 注意: 1、匿名内部类,在【创建对象】的时候,只能使用一次。 如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类。 2、匿名对象,在【调用方法】的时候,只能调用唯一一次。 如果希望给匿名对象,调用多次方法,那么必须给对象起名字。 3、匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】。 匿名内部类与匿名对象不是一回事。类作为成员变量类型:
接口作为成员变量类型: 接口作为方法的参数或返回值: (平均、随机)红包案例Object类: java.lang.Object; 类Object是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。 1、toString方法--------快捷键:Alt+Insert toString() String toString():返回该对象的字符串表示。 toString方法、Random 默认打印地址值,需要覆盖重写 ArrayList、Scanner 默认不是打印地址值 2、equals方法--------快捷键:Alt+Insert equals and hashCode() boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。 默认对比两个人对象的地址值,没有意义 重写equals方法:比较两个对象的属性值(对象的参数,name,age ) 隐含一个多态:Object obj = new Person("焦玉良, 23); 弊端:无法使用子类的特有内容(属性和方法) 解决:向下转型(强转)把Object类转化成Person类 if(this == obj){ return true; } if(obj == null){ return false; } if(obj instanceof Person){ Person p = (Person) obj; //比较两个对象的属性,一个调用方法的this(P1),一个是p(obj = p2) boolean b = this.name.equals(p.name) && this.age == p.age; return b; } return false; String类型防止比较有"null": boolean b = Objects.equals(str1, str2);常用类
表示日期和时间的类:
一、Date类:java.util.Date 类Date表示特定的瞬间,精确到毫秒。 2020-07-26 把日期转化成毫秒: 时间原点(0毫秒):1970年1月1日 00:00:00 System.currentTimeMillis() //时间原点到当前系统时间的毫秒数 把毫秒转化成日期: 1天 = 24 * 60 * 60 * 1000 = 86400,000毫秒 构造方法摘要 1、Date():分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。 in System.out.println(new Date()); out Sun Jul 26 09:54:53 CST 2020 2、Date(long date):传递毫秒值,再转化为Date日期 in System.out.println(new Date(0L)); out Thu Jan 01 08:00:00 CST 1970 成员方法摘要 3、long getTime():把当前系统日期转化为毫秒 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。 二、DateFormat类:java.text.DateFormat 日期/时间格式化子类的抽象类 格式化(也就是日期 -> 文本)、解析(文本-> 日期) 成员方法摘要 1、String format(Date date):将一个 Date 格式化为日期/时间字符串。 2、Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。 Abstract抽象类,不能直接创建对象使用,可以使用它的子类SimpleDateFormat java.text.SimpleDateFormat 构造方法摘要: SimpleDateFormat(String pattern):用给定的模式和默认语言环境的日期格式符号构造 SimpleDateFormat。 y 年 M 月 d 日 H 时 m 分 s 秒 "yyyy-MM-dd HH:mm:ss" "yyyy年MM月dd日 HH时mm分ss秒"1、使用DateFormat类中的format,把日期格式化为文本
String format(Date date); 1)创建SimpleDateFormat对象,构造方法中传递指定的格式 2)调用SimpleDateFormat对象的方法format,按照构造方法中的指定的格式,把Date格式化为字符串(文本)2、使用DateFormat类中的format,把文本格式化为日期
Date parse(String source); 1)创建SimpleDateFormat对象,构造方法中传递指定的格式 2)调用SimpleDateFormat对象的方法parse,按照构造方法中的指定的格式,把字符串(文本)格式化为Date 注意:parse抛出一个ParseException异常 解决:throws继续申明抛出这个异常,或者try...catch自己处理这个异常三、Calender类:java.util.Calendar 日历类
抽象类,不能创建对象。里面有一个静态方法叫getInstance(),该方法返回了一个Calender类的子类对象 static Calendar getInstance():使用默认时区和语言环境获得一个日历。 Calendar c = Calendar.getInstance(); public static final int YEAR年 MONTH月 DATE月中的某一天 DAY_OF_MONTH月中的某一天 HOUR时 MINUTE分 SECOND秒 常用方法: 1、int get(int field):返回给定日历字段的值。 int year = c.get(Calendar.YEAR); 2、void set(int field, int value):将给定的日历字段设置为给定值。 c.set(Calendar.YEAR,9999); //两个参数 void set(int year, int month, int date) c.set(9999,9,9); //三个参数 3、abstract void add(int field, int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。 c.add(Calendar.YEAR,-23); //2020-23=1997 4、Date getTime():返回一个表示此 Calendar 时间值(从历元至现在的毫秒偏移量)的 Date 对象。 Date date = c.getTime(); //Sun Jul 26 15:31:33 CST 2020四、System类:
1、static long currentTimeMillis():返回以毫秒为单位的当前时间。 [测试程序执行效率] long time = System.currentTimeMillis(); 2、static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length): 从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。 参数: src - 源数组。 srcPos - 源数组中的起始位置。 dest - 目标数组。 destPos - 目标数据中的起始位置。 length - 要复制的数组元素的数量。int[] src = {1, 2, 3, 4, 5};int[] dest = {6, 7, 8, 9, 10};System.out.println(Arrays.toString(dest)); //复制前dest:[6, 7, 8, 9, 10]System.arraycopy(src,0, dest, 0,3);System.out.println(Arrays.toString(dest)); //复制后dest:[1, 2, 3, 9, 10]
五、StringBuilder类:字符串缓冲区,提高字符串的操作效率(看成一个长度可变的字符串,未被final修饰)
构造方法: 1、StringBuilder():构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。 StringBuilder bu1 = new StringBuilder(); System.out.println(bu1); //打印:空的 2、StringBuilder(String str):构造一个字符串生成器,并初始化为指定的字符串内容。 StringBuilder bu2 = new StringBuilder("abc"); System.out.println(bu2); //打印:abc成员方法:
1、StringBuilder append(某参数):某参数的字符串表示形式追加到序列。 某参数:任意的数据类型StringBuilder bu1 = new StringBuilder();StringBuilder bu2 = bu1.append("abc");System.out.println(bu2); //打印:abc StringBuilder bu1 = new StringBuilder();bu1.append("abc");bu1.append(12);System.out.println(bu1); //打印:abc12 StringBuilder bu1 = new StringBuilder();bu1.append("abc").append(12); //打印:abc12
链式编程:方法的返回值是一个对象,可以根据对象继续调用方法。
2、StringBuilder reverse():将此字符序列用其反转形式取代。 3、String toString():返回此序列中数据的字符串表示形式。 StringBuilder与String可以相互转化 String->StringBuilder: StringBuilder(String str)构造一个字符串生成器,并初始化为指定的字符串内容。 StringBuilder->String: StringBuilder中的toString方法。 ''' String str1 = sb.toString();六、包装类:
使用一个类,把基本类型的数据包装起来,这个类就是包装类。 在包装类中可以定义一些方法,用来操作基本类型的数据。 装箱与拆箱:基本类型与对应的包装类对象之间的来回转换。 装箱:(Integer举例) 构造方法: 1、Integer(int value):构造一个新分配的 Integer 对象,它表示指定的 int 值。 ''' Integer i = new Integer(1); System.out.println(i); //打印:1 2、Integer(String s):构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。 静态方法: 1、static Integer valueOf(int i):返回一个表示指定的 int 值的 Integer 实例。 ''' Integer i = Integer.valueOf("1"); System.out.println(i); //打印:1 2、static Integer valueOf(String s):返回保存指定的 String 的值的 Integer 对象。 拆箱:(Integer举例) 成员方法: int intValue():以 int 类型返回该 Integer 的值。 ''' Integer i = new Integer(1); int j = i.intValue(); System.out.println(j); //打印:1 自动装箱与自动拆箱:基本类型的数据和包装类之间可以自动的互相转换
Integer in = 1; //等价于 Integer in = new Integer(1);//in是包装类,无法直接参与运算,可以自动转化为基本类型的数据,再参与计算in = in + 2; //in + 2 等价于 in.intValue() + 2 = 3;//in = in + 2;等价于 in = new Integer(3);System.out.println(in); //打印:3
基本类型与字符串之间的转化:(基本类型为int举例)
基本类型->字符串: 1、基本类型的数据值 + "" //*推荐 ''' String str1 = 12 + ""; System.out.println(str1 + 200); //打印:12200 2、使用包装类的静态方法。 static String toString(int i):返回一个表示指定整数的 String 对象。 ''' String str2 = Integer.toString(12); System.out.println(str2 + 300); //打印:12300 3、使用String类中的静态方法。 static String valueOf(int i):返回 int 参数的字符串表示形式。 ''' String str3 = String.valueOf(12); System.out.println(str3 + 400); 打印:12400 字符串->基本类型: 使用包装类中的静态方法。 static int parseInt(String s):将字符串参数作为有符号的十进制整数进行解析。 ''' int num = Integer.parseInt("12"); System.out.println(num + 500); //打印:512 Collection集合: java.util.Collection; [无索引]框架: Collection 接口 List Set 接口 ArrayList LinkedList Vector HashSet TreeSet 类 LinkHashSet 类
方法介绍:
'''创建集合对象(多态) Collection<String> coll = new ArrayList<>(); 1、boolean add(E e):确保此 collection 包含指定的元素(可选操作)。 2、boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 3、boolean contains(Object o):如果此 collection 包含指定的元素,则返回 true。 4、boolean isEmpty():如果此 collection 不包含元素,则返回 true。 5、void clear():移除此 collection 中的所有元素(可选操作)。 6、int size():返回此 collection 中的元素数。 7、object[] toArray():返回包含此 collection 中所有元素的数组。 ''' object[] arr = coll.toArray();Iterator接口(迭代器):
迭代:Collection集合元素的通用获取元素。先判断集合有没有元素,有取出,继续判断,有再取出,直到全部取出。 **该接口无法直接使用,需要Iterator接口实现类对象,获取实现类比较特殊,Collection接口有一个方法叫iterator(), 这个方法返回就是迭代器的实现类对象。 Iterator<E> iterator():返回在此 collection 的元素上进行迭代的迭代器。 迭代器的使用步骤: 1、先使用Collection集合中的方法iterator()获取迭代器的实现对象,使用Iterator接口接收(多态) 2、使用Iterator接口中的hasNext()方法判断有没有下一个元素 3、用Iterator接口中的next()方法取出下一个元素 方法介绍; 1、boolean hasNext():如果仍有元素可以迭代,则返回 true。 2、E next():返回迭代的下一个元素。Collectioncoll = new ArrayList<>();coll.add("迪丽热巴");Iterator it = coll.iterator();while (it.hasNext()){ String str = it.next(); System.out.println(str);}
使用:for(Iterator<String> it = coll.iterator();it.hasNext();){...}
增强for循环:专门用来遍历集合和数组的。低层是Iterator迭代器,遍历过程不能对其中的元素增删操作。 public interface Collection<E> extends Iterable<E> 所有单列集合都可以用增强for public interface Iterable<T> 实现这个接口允许对象成为 "foreach" 语句的目标。 格式: for(集合/数组的数据类型 : 集合名/数组名){ sout(变量名); }int[] arr = {1, 2, 3, 4, 5};for(int i : arr){ System.out.println(i);}ArrayListarr = new ArrayList<>();arr.add("abc");arr.add("def");arr.add("ghi");for(String str : arr){ System.out.println(str);}
泛型:一种未知的数据类型,不知道使用什么数据类型的时候,可以使用泛型。也可以看成一个变量,接收数据类型。
E e:Element 元素 T t:Type 类型 比如:ArrayList<E> 创建集合对象的时候,就会确定泛型的数据类型。创建集合对象不使用泛型:默认类型为Object类型,可以存储任意类型的数据。但是不安全,会引发异常。
创建集合对象使用泛型:避免了类型转化的麻烦,存储什么类型,取出就是什么类型。 但是泛型什么类型,只能存储什么类型。 定义和使用含有泛型的类://定义和使用含有泛型的类 模拟ArrayListpublic class GenericClass{ private E name; public E getName() { return name; } public void setName(E name) { this.name = name; }}
定义和使用含有泛型的方法:
定义在修饰符和返回值类型之间。 格式: 修饰符 <泛型> 返回值类型(参数列表(使用泛型)){ 方法体; }public class GenericMethod { publicvoid method1(M m){ System.out.println(m); } public static void method2(S s){ System.out.println(s); }}
定义和使用含有泛型的接口:
//GenericInterface接口 public interface GenericInterface { public abstract void method(I i); }//GenericInterfaceImpl接口实现的对象1 //第一种方式:定义接口的实现类,实现接口,指定接口的泛型 public class GenericInterfaceImpl implements GenericInterface{ @Override public void method(String s) { System.out.println("这是重写接口的第一种方法" + s); } } //GenericInterfaceImpl_2接口实现的对象2 //第二种方式:接口使用什么泛型,实现类就使用什么泛型,类跟着接口走。 //就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。 public class GenericInterfaceImpl_2 implements GenericInterface { @Override public void method(I i) { System.out.println("这是重写接口的第二种方法" + i); } }//demo06GenericInterface主函数main中调用 //第一种 GenericInterfaceImpl gi = new GenericInterfaceImpl(); gi.method("abc"); //第二种 GenericInterfaceImpl_2 gi2 = new GenericInterfaceImpl_2<>(); gi2.method("6662jd");
泛型通配符:
不知道使用什么类型来接收的时候,此时可以使用?,表示未知通配符。 此时只能接收数据,不能往该集合中存储数据。 使用方式: 不能创建对象使用,只能作为方法的参数使用。//main外面的方法 private static void demo01(ArrayList arr) { Iterator it = arr.iterator(); while(it.hasNext()){ Object o = it.next(); System.out.println(o); } }
通配符高级使用---受限泛型 [看的懂就可以]
泛型的上限限定:? extends E 代表使用的泛型只能是E类型的子类/本身 泛型的下限限定:? super E 代表使用的泛型只能是E类型的父类/本身public class demo08Generic { public static void main(String[] args) { Collectionlist1 = new ArrayList<>(); Collection list2 = new ArrayList<>(); Collection list3 = new ArrayList<>(); Collection
数据结构:
栈(stack):先进后出 队列(queue):先进先出 数组(array):查询快-地址是连续的。增删慢-长度是固定的。 链表(Linked List):查询慢-地址不连续。增删快-元素增删后对整体结构没影响。 每一个元素称为一个节点,一个节点包含一个数据源(存储数据),两个指针域(存储地址)。 单向链表:不能保证元素的顺序(存储元素和取出元素的顺序有可能不一致) 双向链表:有一条链子是专门记录元素的顺序,是一个有序集合 红黑树(binary tree):趋近于平衡树,查询的速度非常快,查询叶子节点最大次数和最小次数不能超过2倍。List集合:public interface List<E> extends Collection<E>
有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。 用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。 特点: 1、有序的集合,存取元素和取出元素的顺序使一致的 2、有索引,包含了一些带索引的方法 3、允许存储重复的元素 带索引的(特有)方法: 1、void add(int index, E element):在列表的指定位置插入指定元素(可选操作)。 2、E get(int index):返回列表中指定位置的元素。 3、E remove(int index):移除列表中指定位置的元素(可选操作)。 4、E set(int index, E element):用指定元素替换列表中指定位置的元素(可选操作)。 ''' //创建一个List集合对象,多态 List<String> list = new ArrayList<>();ArrayList集合:多线程,查询快,增删慢
LinkedList集合:多线程,低层是一个链表结构,大量对首尾操作的方法,查询慢,增删快 注意:使用特有方法的时候,不能使用多态 1、void addFirst(E e):将指定元素插入此列表的开头。 2、void addLast(E e):将指定元素添加到此列表的结尾。 3、void push(E e):将元素推入此列表所表示的堆栈。((0号元素增加,相当于addFirst) 4、E getFirst():返回此列表的第一个元素。 5、E getLast():返回此列表的最后一个元素。 (增加一个isEmpty判断安全些) 6、E removeFirst():移除并返回此列表的第一个元素。 7、E removeLast():移除并返回此列表的最后一个元素。 8、E pop():从此列表所表示的堆栈处弹出一个元素。 (0号元素删除,相当于removeFirst) ''' //创建LinkedList集合的对象 LinkedList<String> link = new LinkedList<>(); Vector集合:可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。单线程。 Set接口:public interface Set<E> extends Collection<E> 特点: 1、不允许存储重复元素 2、没有索引,没有带索引的方法,也没有普通的for循环HashSet集合:
特点:无重复元素、没索引、无序集合(存取元素顺序可能不一致)、低层是哈希表结构(查询快) ''' Set<Integer> set = new HashSet<>(); 遍历用:迭代器、增强for 哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址, 是模拟出来的地址,不是数据存储的队伍里地址) 在Object类中有一个方法,可以获取对象的哈希值: int hashCode():返回该对象的哈希码值。哈希表:
哈希表=数组+链表 =数组+红黑树(提高查询速度) Set集合存储元素不重复的原理: Set集合在调用add方法的时候,add方法先会调用元素的hashCode方法和equals方法,判断元素是否重复。HashSet存储自定义类型元素:
重写hashCode方法和equals方法。LinkedHashSet集合:具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
低层是一个哈希表(数组+链表/红黑树)+链表;多了一个链表(记录元素的存储顺序),保证元素有序。可变参数:
使用前提:当方法参数列表数据类型已经确定,但是参数的个数不确定,就可以用可变参数。 使用格式:(定义方法时使用) 修饰符 返回值类型 方法名(参数类型...形参名){} 修饰符 返回值类型 方法名(参数类型[] 形参名){} 可变参数的原理: 可变参数低层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数 传递参数的个数可以是0个(不传参),1,2...多个。 注意: 1、一个方法的参数列表只能有一个可变参数 2、如果方法参数有多个,那么可变参数必须写在参数列表的末尾 可变参数的终极写法: public static void method(Object...obj){}public class demo05VarArgs { public static void main(String[] args) { System.out.println(add(3,3)); //6 System.out.println(add(3,3,6)); //12 System.out.println(add(3,3,2,5,3,8)); //24 } private static int add(int...arr) { int sum = 0; for (int i : arr) { sum += i; } return sum; } }
Collections集合工具类:
1、static <T> boolean addAll(Collection<? super T> c, T... elements):将所有指定元素添加到指定collection中。 2、static void shuffle(List<?> list):使用默认随机源对指定列表进行置换。ArrayListlist = new ArrayList<>();Collections.addAll(list,"a", "b", "c", "d");Collections.shuffle(list);
3、static <T> void sort(List<T> list):根据元素的自然顺序 对指定列表按升序进行排序。
使用前提:被排序的集合里面存储的元素,必须实现Comparable,重写接口的方法compareTo定义排序规则。 comparable接口排序规则:自己(this)- 参数 就是升序排序public class Person implements Comparable{ ... //重写排序的规则 @Override public int compareTo(Person o) { //自定义规则,比较两个人的年龄(this,参数Person) return this.getAge() - o.getAge(); //年龄升序排序 } }
4、static <T> void sort(List<T> list, Comparator<? super T> c):根据指定比较器产生的顺序对指定列表进行排序。 Comparable与Comparator的区别:
Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较的规则compareTo Comparator:相当于找一个第三方的裁判,比较两个人ArrayListlist = new ArrayList<>(); Collections.addAll(list,2,5,3,4); System.out.println(list); //[2, 5, 3, 4] Collections.sort(list, new Comparator () { //重写比较规则 @Override public int compare(Integer o1, Integer o2) { return o1 - o2; //升序 } }); System.out.println(list); //[2, 3, 4, 5]
Map集合:
Map<K,V>类型参数: K - 此映射所维护的键的类型 V - 映射值的类型 特点: 1、Map集合是一个双列集合,一个元素包含两个值(一个key,一个value) 2、Map集合中的元素,key和value的数据类型可以相同,也可以不同 3、Map集合中的元素,key是不允许重复的,但是value是可以重复的 4、Map集合中的元素,key和value是一一对应的Map的常用子类:
HashMap<K,V>集合: 1、低层是哈希表:查询快。 2、无序的集合,存取元素顺序可能不同。 LinkedHashMap<k,v>集合 extends HashMap<k,v>集合 1、低层是哈希表+链表(保证迭代的顺序) 2、有序的集合,存取元素的顺序一致的 Map接口中常用方法: 1、V put(K key, V value):将指定的值与此映射中的指定键关联(可选操作)。[可以不接收返回] 返回值V:存储键值对的时候,key不重复,返回值V是null;key重复,会使用新的value替换已有的值,返回被替换的value ''' //创建Map集合对象,多态 Map<String,String> map = new HashMap<>(); String v1 = map.put("liChen", "fanBing1"); System.out.println(v1); //null String v2 = map.put("liChen", "fanBing2"); System.out.println(v2); //fanBing1 System.out.println(map); //{liChen=fanBing2} 2、V remove(Object key):如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 返回值V:key存在,v返回被删除的值;key不存在,返回值是null 3、V get(Object key):返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 返回值V:key存在,返回value的值;key不存在,返回值是null 4、boolean containsKey(Object key):如果此映射包含指定键的映射关系,则返回 true。 Map集合遍历键找值方式: 5、Set<K> keySet():返回此映射中包含的键的 Set 视图。 步骤: 1、使用Map集合的方法keyset(),把Map集合所有的key取出来,存储到set中 2、遍历set集合,获取Map集合中的每一个key。 3、通过Map集合中的方法get(key),通过Key找value。 ''' Map<String, Integer> map = new HashMap<>(); map.put("ZhangSan",18); map.put("LiSi",17); map.put("WangWu",28); Set<String> strs = map.keySet(); //增强for for (String str : strs) { Integer value = map.get(str); System.out.println("key:" + str + ";Value:" + value); } 6、Set<Map.Entry<K,V>> entrySet():返回此映射中包含的映射关系的 Set 视图。 Entry键值对对象: 作用:当Map集合一创建,那么就会在Map集合中一个Entry对象,用来记录键与值(键值对对象、键与值的映射关系) 把Map集合内部的多个Entry对象取出来存储到一个set集合中。 Entry的方法: K getKey():返回与此项对应的键。 V getValue():返回与此项对应的值。Map集合遍历键值对方式:
''' Map<String, Integer> map = new HashMap<>(); map.put("ZhangSan",18); map.put("LiSi",17); map.put("WangWu",28); Set<Map.Entry<String, Integer>> set = map.entrySet(); //迭代器 Iterator<Map.Entry<String, Integer>> it = set.iterator(); while(it.hasNext()){ Map.Entry<String, Integer> entry = it.next(); String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + "--->" + value); }HashMap存储自定义类型键值:
Map集合保证key是唯一的:作为key元素,必须重写hashCode和equals方法,以保证key唯一。LinkedHashMap集合:public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 有序的集合
HashTable集合:public class Hashtable<K,V> implements Map<K,V>
特点: 单线程安全的,速度慢。(与HashMap相反) key、value都不能为空。(与HashMap相反) 子类Properties集合是一个唯一的与IO流相结合的集合。JDK9的of方法:
List接口、Set接口、Map接口,静态方法of,可以给集合一次性添加多个元素 使用前提:当集合中的元素的个数已经确定了,不再改变时使用。 注意:of方法只用于List、Set、Map接口,不适用于接口的实现类 of的方法返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素 Set、Map调用不能有重复的元素 ''' List<String> list = List.of("a","b","c","d","e");DeBug追踪:
可以让代码逐行执行,查看代码执行全过程,调试程序中的BUG异常: Throwable->Error、Exception
Exception:编译期异常,进行编译(写代码)java程序出现的问题 RuntimeException:运行期异常,java运行过程出现的异常 throw关键字:在指定的方法中抛出指定的异常-参数校验 格式:throw new xxxException("异常产生的原因"); 注意:必须写在方法内部、new的对象是Exception或它的子类对象 throw关键字后创建的是编译异常,必须处理,用throws或者try...catch 文件找不到异常:FileNotFoundException throw关键字后创建的是RuntimeException及其子类可以不处理,默认交给JVM打印,中断 空指针异常:NullPointerException 数组索引越界异常:ArrayIndexOutOfBoundsExceptionObjects非空判断:(静态方法)
public static <T> T requireNonNull(T object);查看指定索引对象是不是空。 ''' public static void main(String[] args) { method(null); } public static void method(Object obj){ /*if(obj == null){ throw new NullPointerException("传递对象是null"); }*/ Objects.requireNonNull(obj, "传递对象是null"); }throws关键字:异常处理第一种方式-交给别人处理
格式:修饰符 返回值类型 方法名(参数列表) throws xxxException...{ throw new xxxException("异常原因:xxxException"); ... } 注意:必须写在方法声明处、声明的异常是Exception或它的子类对象(多个异常:直接写父类异常) 必须处理-继续使用throws,交给方法调用者处理,再给JVM -try...catch自己处理 ''' public static void main(String[] args) throws FileNotFoundException,IOException { readFile("C:\\b.txt"); } public static void readFile(String fileName) throws FileNotFoundException,IOException { if(!fileName.equals("C:\\a.txt")){ throw new FileNotFoundException("文件路径错误"); } if(!fileName.endsWith(".txt")){ throw new IOException("文件后缀错误"); } System.out.println("文件没问题,读取文件"); }try...catch:异常处理第一种方式-自己处理异常
格式: try{ 可能产生异常的代码; } catch(定义一个异常变量,接收try抛出的异常对象){ 异常处理逻辑,异常之后怎么处理异常对象 工作中:异常信息记录在日志里 } ... catch(异常类名 变量名){ ... }Throwable异常处理的3个方法:
1、String getMessage():返回此 throwable 的简短描述。 2、String toString(): 返回此 throwable 的详细消息字符串。 3、void printStackTrace():将此 throwable 及其追踪输出至标准错误流。 ''' try { readFile("C:\\a.tct"); } catch (IOException e) { System.out.println(e.getMessage());//文件后缀错误 System.out.println(e.toString());//java.io.IOException: 文件后缀错误 e.printStackTrace();//java.io.IOException: 文件后缀错误 //at Demo0802.demo5Throwable.readFile(demo5Throwable.java:24) //at Demo0802.demo5Throwable.main(demo5Throwable.java:14) }finally代码块:一些特定的代码无论是否异常都要执行
格式: try{ ... }catch(){ ... }finally{ 无论是否异常都会执行 } 注意:与try一起使用,资源释放IO流 如果finally有return语句,那么返回的就是finally的结果(避免finally中写return)多个异常的捕获处理:
1、多个异常分别处理 多个try...catch 2、多个异常一次捕获,多次处理 一个try,多个catch [异常变量有子父类关系,子类写在前,否则会报错] 3、多个异常一次捕获,一次处理 catch(Exception e){ ... } [可以不处理] 子类重写父类方法时,抛出和父类一样的异常 抛出父类异常的子类 不抛出异常 父类方法没有抛出异常,子类重写父类方法也不可能抛出异常 此时子类产生该异常,只能捕获处理,不能声明抛出自定义异常类:
格式: public class XXXException extends Exception | RuntimeException { 添加一个空参数的构造方法 添加一个带异常信息的构造方法 }并发:指两个或者多个事件在同一个时间段内发生。---交替执行
并行:指两个或者多个事件在同一个时刻发生(同时发生)。---同时执行进程:进入到内存中的程序线程:CPU执行程序的路径 线程属于进程,是进程的一个执行单元,负责程序的执行线程调度:分时调度,抢占式调度主线程:main<=>cpu
创建多线程程序:(第一种方式)
1、创建一个Thread子类 2、在Thread子类中重写run方法,设置线程任务 3、创建Thread类的子类对象 4、调用Thread类中的方法start方法,开启新的线程,执行run方法。void start():使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
Thread类的常用方法:
获取线程的名字: 1、使用Thread类中的getName() String getName():返回该线程的名称。 2、先获取到当前正在执行的线程,使用线程中的方法getName()获取线程名称 static Thread currentThread():返回对当前正在执行的线程对象的引用。 ''' Thread.currentThread().getName(); 主线程:main 新线程:Thread-0... 设置线程的名称: 1、使用Thread类中的setName() void setName(String name):改变线程名称,使之与参数 name 相同。 2、创建一个带参数的构造方法,重写MyThread类->把线程名称传递给父类,让父类给子线程起一个名字。 Thread(String name):分配新的 Thread 对象。 MyThread里重写构造方法: public MyThread(String name) { super(name); } static void sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行), 此操作受到系统计时器和调度程序精度和准确性的影响。 ''' Thread.sleep(1000);创建多线程程序:(第二种方式)实现Runnable接口
''' public class RunnableImpl implements Runnable{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName() + "->" + i); } } } ''' public class demo10Runnable { public static void main(String[] args) { RunnableImpl run = new RunnableImpl(); new Thread(run).start(); for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName() + "->" + i); } } } 匿名内部类创建线程: ''' public static void main(String[] args) {new Thread(){
@Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName() + "->" + i); } } }.start();Runnable run = new Runnable(){
@Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName() + "->" + i); } } }; new Thread(run).start();new Thread(new Runnable() {
@Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName() + "->" + i); } } }).start();}
解决线程安全问题:
线程同步:同步代码块、同步方法、锁机制。发表评论
最新留言
关于作者
