1.什么是编程语言?
开发于sun公司,现属oracle
人与计算机沟通交流的一种特殊语言
詹姆斯·高斯林 java语言创始者
配置环境变量:
jdk
java开发工具包
jre
java运行时环境
jvm
java虚拟机
java程序执行过程:
1.先编写java源代码 javac.exe
2.对java源代码进行编译 javac
源文件名称
编译完成后会生成当前源文件所生成的字节码文件.class
字节码文件是开发人员看不懂的, 只有jvm
虚拟机才能识别
3.运行java代码 java.exe
java 类名
java语言是支持跨平台的:用java编写的源代码可以在不同的系统 上运行
使用JDK开发完成的java程序,交给JRE去运行
java语法规范
1.类和接口要声名一个标识符用大驼峰命名法
2.变量和方法要声名标识符用小驼峰命名法
注释:
编译器中按住alt可以选择一列
#快捷键 ctrl + shift + /
单行注释://注释文字
多行注释:/* 注释文字 */
文档注释:/** 注释文字 */
61class Hello{
2 public static void main(String[] args){
3 System.out.println("Hello world");
4 }
5}
6//java最基本的Hello world
在程序执行的过程中其值不可以发生改变
在方法外面定义,全大写,单词与单词之间用下划线分隔开
java是一门强类型语言,对于每一种数据都定义了明确的具体数据类型
在内存总分配了不同大小的内存空间
数据类型
1.基本数据类型:
a.数值型:整数类型(byte,short,int,long
)
浮点类型(float,double
)
b.字符型:(char
)
c.布尔型:(boolean
)
2.引用数据类型:
a.类: (class
)
b.接口:(interface
)
c.数组: ([ ]
)
101double d = 3.14;
2
3float f = 3.14f;
4
5char c = 'q';
6
7String s = "hello world";
8//String是引用数据类型
9
10boolean b = false;
有几个数据类型关键字就开辟几份内存空间
强制转换:
21double d =3.14;
2int i = (int)d;
运算符+ - * / %(取余)
191num++;
2//后置++,先取值再赋值
3--num;
4//前置--,先赋值再取值
5d1 += d2 -> d1 = d1 + d2;
6"Hello" instanceof String //结果true,检查是否是类的对象
7
8 //与运算 两者同时为真结果为真
9 if (1 > 2 & 1 == 2);
10 //不短路 false & false
11 if (1 > 2 && 1 == 2);
12 //短路运算 false && 不运算
13
14//或运算 两者只要有一者为真,结果为真
15if (1 < 2 | 2 < 3);
16if (1 <2 || 2 < 3);
17//非运算,取反
18(1 > 2) -> false !(1 > 2) -> true
19
成员变量:实例变量,静态变量
在JVM虚拟机的栈内存开辟空间,但静态变量在方法区空间开辟内存
局部变量:方法体内部的变量(包括参数中的变量)
JAVA对类的定义:
java本身是面向对象的语言,如果需要使用java去开发一个软件**
那么,软件中的每一个模块都是一个个体,每一个个体会拆分为很多单元,每个单元本身
是一个模糊的概念,针对这样的一个概念,我们一般用类去定义,然后在具体执行的时候,
需要让模块之间相互协作,正常的去模拟现实生活中场景的时候,就需要创建这个类
所对应的实例
将鼠标光标放置于未被导入的包名称上,按住alt + Enter 可以快速import包 (IntelliJ IDEA支持)
创建类
new关键字 创建类的实例
创建类实例的对象
对象.调用方法
方法是完成特定功能的代码块
格式:
721 修饰符 返回值类型 方法名(参数类型 参数名1, 参数类型 参数名2..){
2 函数体;
3 return 返回值;
4}
5
6
7
8package com.tly.test;
9
10/**
11 * 第一个简单java小程序,输入三个浮点数,求最小值
12 */
13
14import java.util.Scanner;
15
16public class Test02 {
17 public static void main(String[] args) {
18
19 //创建Test02的对象
20 Test02 getMinNum = new Test02();
21
22 //接收输入的浮点数据
23 Scanner scanner = new Scanner(System.in);
24
25 System.out.println("请输入第一个浮点数据类型:");
26
27 //创建一个浮点型变量接收返回的参数
28 double num1 = scanner.nextDouble();
29
30 System.out.println("请输入第二个浮点数据类型:");
31
32 double num2 = scanner.nextDouble();
33
34 System.out.println("请输入第三个浮点数据类型:");
35
36 double num3 = scanner.nextDouble();
37
38 //调用对象的方法并传输传输
39 double numMin = getMinNum.getMinNum(num1, num2, num3);
40
41 System.out.println("最小值为:"+numMin);
42
43 }
44
45 //创建类的getMinNum方法
46 public double getMinNum(double num1,double num2, double num3){
47
48 double[] doubles = new double[3];
49
50 //将数据传输给列表
51 doubles[0] = num1;
52 doubles[1] = num2;
53 doubles[2] = num3;
54
55 //创建中间值
56 double numMin = num1;
57
58 for (int i = 0; i < doubles.length; i++) {
59
60 if(doubles[i] < numMin){
61
62 numMin = doubles[i];
63
64 }
65
66 }
67
68 return numMin;
69 }
70}
71
72
方法特性:
递归:
使用递归会严重损耗系统资源,因此要尽量避免使用递归
方法的重载:
在一个区间内,java语法中运行方法名称相同,参数列表不同的语法格式,这种现象我们称之为重载
在参数中的位置只能出现在最后 格式:数据类型...
可变长参数本质其实就是一个数组
可变长参数数值可以传也可以不传,也可以传多个
new创建的容器存放在堆内存中
数组是一个引用数据类型
可以通过new的方式去创建数组
在不赋值的情况下,取到的是默认值,整型默认值是0
261//创建数组
2int[] ints = new int[10];
3
4//给数组赋值
5ints[0] = 100;
6
7//遍历数组
8for (int i = 0; i < ints.length; i++){
9
10 System.out.println(ints[i]);
11
12}
13
14//创建字符串数组
15String[] strings = new String[5];
16
17//赋值
18String[0] = "hello";
19
20//foreach遍历
21//for (数据的数据类型 遍历的每一项 : 容器对象)
22for (String str : strings){
23
24 System.out.println(str);
25
26}
数组操作常见的小问题:
91数组索引越界
2
3 -ArrayIndexOutOfBoundsException
4
5 -访问到了数组中的不存在的索引时发生。
6
7空指针异常
8 -NullPointerException
9 -数组引用没有指向实体,却在操作实体中的元素时。
字符串常用函数
561//定义字符串
2String str = "hello world";
3
4//str.equals() 判断字符是否完全匹配
5System.out.println(str.equals("hello world"));
6//输出true
7
8//str.contains()判断是否包含某一字符串
9System.out.println(str.contains("hello"));
10//输出true
11
12//str.substring()切割字符串 int beginIndex
13System.out.println(str.substring(6));
14//输出world 切割[0,6)
15
16System.out.println(str.substring(6,11));
17//输出world 切割(6,11]
18
19//str.toLowerCase()将大写字母转成小写
20System.out.println(str.toLowerCase());
21
22//str.length() 获取字符串字符个数
23System.out.println(str.length());
24//输出11
25
26//str.endsWith()判断字符串是否以某个字符串结尾
27System.out.println(str.endsWith("d"));
28//输出true
29
30//str.split()字符串的分割
31String[] strings = str.split(" ");
32
33//遍历数组
34for (String s:strings){
35
36 System.out.println(s);
37
38}
39//输出hello
40//输出world
41
42//将字符串转为字符数组
43char[] chars = str.toCharArray();
44
45for (String c:chars){
46
47 System.out.println(c);
48
49}
50
51//str.replace()字符串替换方法
52String str4 = str.replace("world","java");
53System.out.println(str4);
54//输出hello java
55
56
以后我们开发项目的时候,要不断的去声明类,在类中需要去封装属性和行为,
但是针对某一些属性,我们需要将它保护起来,不希望直接对外界提供访问。
所以我们会将这些属性用private关键字进行修饰,private代表的是私有的访问权限修饰符。
被private修饰的属性只能在本类中才能访问到
alt + INS键快速选择创建类的get方法与set方法
xxxxxxxxxx
261public class User {
2
3 private String userName;
4
5 private String address;
6
7 private String idCard;
8
9 private String phoneID;
10
11 //提供一个idCard对应的get方法,没有参数,但是有返回值
12 public String getIdCard(){
13
14 return idCard;
15
16 }
17
18 //提供一个idCard对应的set方法,有参数,但是没有返回值
19 public void setIdCard(String idCard){
20
21 this.idCard = idCard;
22
23 }
24
25
26}
栈内存:主函数,定义的普通函数,基本数据类型,数据地址(引用数据类型的地址),所有的方法
堆内存:new出来的对象,应用数据类型的值
方法区内存:方法区内存中一般存放的是代码片段(java源文件编译之后的字节码文件),以及常量池
静态方法存在栈内存中,静态变量存在于方法区内存中
定义在类中的实例变量一定是在堆内存中开辟的空间,因为new出来的部分一定存在于堆内存中。
在JVM内存中,所有的方法,无论是静态方法还是普通方法(实例方法),都是在栈中分配空间。
局部变量是存在于方法体内部的变量(包含了参数),局部变量如果是基本数据类型,则直接在栈中开辟空间,如果是引用数据类型,变量声明部分在栈中,实例创建部分在堆中,如果是实例遍历,所有的内存都会在堆中去开辟。
常量池一般存储字符串常量
Java中通过 == ,如果比较的是基本数据类型,比的是值,如果比较的是引用数据类型,则比较的是内存地址
是一个权限修饰符
可以修饰成员(成员变量和成员方法)
被private修饰的成员只能在本类中才能访问
this:代表所在类的对象的引用(方法被哪个对象调用,this就代表那个对象)
this.变量名 访问的是本类中的实例变量
作用:给对象的数据进行初始化
方法名与类名相同,没有返回值类型,连void也没,没有具体的返回值
如果不提供构造方法,那么系统会给出默认的构造方法,如果提供了构造方法(不管是否带参数),系统将不再提供默认无参数的构造方法
构造方法可以重载
构造方法的作用:
无参构造:实例化对象,但是实例化对象后,所有的属性都是没有被赋值的
有参构造:实例化对象,可以在创建对象时,就给实例的属性赋值
可以修饰方法,可以修饰属性,但是不能修饰类
被静态关键字修饰的属性和方法,会成为一个类级别的元素,会随着类的加载而加载
局部变量不能被static修饰
被static修饰的变量我们称之为静态变量
静态变量会随着类的加载而加载,在JVM解析字节码文件时,该变量的内存空间就会被开辟出来
静态变量的内存空间会被开辟在该方法区中
静态方法:
xxxxxxxxxx
311public class StaticTest01{
2
3 private static String name; //静态变量
4
5 public static void main(String[] args){
6
7 //调用静态方法
8 StaticTest01.getMethod();
9
10 StaticTest01 staticTest01 = new StaticTest01();
11
12 //调用实例方法
13 staticTest01.getMethod02();
14 }
15
16 //声明一个静态方法
17 public static void getMethod(){
18
19 System.out.println("我是一个静态方法!");
20
21 }
22
23 public void getMethod02(){
24
25 System.out.println("我是一个静态方法!");
26
27 }
28
29}
30
31
在类加载的时候将会被执行的语句体,而且只加载一次(在主函数执行前执行)
xxxxxxxxxx
51static{
2
3 System.out.println("static 执行了!!");
4
5}
getXxx()
setXxx()
setXxx()
概述:多个类中存在相同的属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
通过extends关键词可以实现类与类的继承
class 子类名 extends 父类名 {}
单独的这个类称为父类,基类,或者超类;这多个类可以称为子类或者派生类
###
继承可以让子类去继承父类,这样子类会继承父类所有的属性和方法,在java中是不允许有多继承的
Object类:是java中的祖宗类,当一个类在代码层面没有去继承任何的父类,那么这个类
默认会继承Object类
继承的重写(覆盖):
子类继承父类以后,可以获取到父类所有的方法(包含被private修饰的私有方法,但是访问不到)
如果父类方法的功能不能够满足子类的需求,这个时候,子类可以针对这个方法进行重写
父类中私有方法不能被重写
子类重写父类方法时,访问权限不能更低
父类静态方法,子类也必须通过静态方法进行重写
提高了代码的复用性
提高了代码的维护性
让类与类之间产生了关系,是多态的前提
不要为了部分功能而去继承 ,继承中类之间的体现是“is a”的关系
继承中成员变量的关系
在子类方法中访问一个变量:
子类继承父类之后,子类可以通过super关键字去指向父类的元素(属性,普通方法,构造方法)
如果指向父类的构造用super() 如果指向子类的构造用 this()
xxxxxxxxxx
281public class Student extends Person{
2
3 public Student(){
4
5 //指向的是父类的无参构造,不写则默认存在
6 super();
7
8 }
9
10
11 public void sleep(){
12
13 //指向父类的普通方法,只能存在于子类构造中
14 super.sleep();
15
16 }
17
18 public void getMethod(){
19
20 //this指向当前类实例的属性
21 System.out.println(this.name);
22
23 //super指向父类的属性
24 System.out.println(super.name);
25
26 }
27
28}
子类中所有的构造方法默认都会访问父类中的空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据
所以,子类初始化之前,一定要先完成父类数据的初始化
每一个构造方法的第一条语句默认都是:super()
方法重写与方法重载的区别?方法重载能改变返回值类型吗?
答:方法重写建立在类的继承关系上,是对父类同名方法的覆盖。方法重载是一个类中,多个同名方法,但是参数列表不同。方法重载可以改变返回值类型。
某一事物,在不同时刻表现出来的不同状态
多态是面向对象特征之一,也是最重要的一个特征
多态思想:
为了解除类与类之间的耦合(模块与模块之间的耦合),不能面向具体编程,而要面向抽象编程(面向接口编程)
首先多态必须要有父子关系的体现(继承,实现),是在不同时刻展现出不同的状态
父类的引用接收子类对象(向上转型),或者是向下转型都是多态的体现
多态在程序执行时分为编译阶段和运行阶段:
普通方法:
编译阶段看左边:编译时要检查调用的方法在父类中是否存在
运行阶段看右边:因为我们实际new出来的对象是子类对象,所以最终执行的方法也是子类的方法
静态方法:
静态方法可以用类名去调用,类名.静态方法名()
静态方法也可以用实例去调用,对象引用.静态方法名(),本质也是通过类名去调用
静态方法是一个类级别的方法,所以它已经脱离了实例,和对象没有关系
编译看左边,运行看左边
xxxxxxxxxx
331class PloyTest01{
2
3 public static void main(String[] args){
4
5 Cat cat = new Cat();
6
7 //通过多态机制来创建猫的实例
8 Animal animal = new Cat();
9
10 animal.eat();
11
12 //引用数据类型的强转就是多态的一种,向上转型
13 Animal animal1 = (Animal)cat;
14
15 //面试题:
16 Animal animal = new Rabbit();
17
18 //判断animal1是否属于Cat,属于则进行强转
19 if (animal1 instanceof Cat){
20
21 //向下转型
22 Cat cat1 = (Cat)animal1;
23
24 cat1.eat();
25
26 }
27
28
29
30
31 }
32
33}
多态前提和体现
有继承关系
有方法重写
有父类引用指向子类对象
多态在开发中的作用
主任喂养宠物的案例:
有一个主人是master喜欢喂养宠物,喂养的宠物有很多种(猫,狗,兔子,鸟),然后随着时间的推 移,主人会喂养越来越多的宠物,针对于这样的场景我们通过java程序去模拟一下(体现出多态)
重载算不算多态?不算多态(没有体现父子关系)
结论:如果按照传统的方式进行开发(不使用多态):会发现程序进行迭代的时候,需要去修改主人类(需要在原有的代码继承上进行修改),这样做违背了设计模式中的开辟原则(OCP 对扩展开发,对修改关闭):在写程序的时候,尽量避免在原有的代码之上进行修改,这样的话修改的部分容易对别的类(或者说别的模块造成影响)
xxxxxxxxxx
661public class Master {
2
3 //这是一个喂养的方法,用父类的引用去接收子类的对象
4 public void feed(Pet pet){
5
6 pet.eat();
7
8 }
9
10}
11
12//创建抽象类Pet
13public class Pet {
14
15 public void eat(){
16
17 System.out.println("所有的宠物都有吃的特性");
18
19
20 }
21
22}
23
24
25public class Cat extends Pet{
26
27 public void eat(){
28
29 System.out.println("猫吃鱼");
30
31 }
32
33}
34
35public class Rabbit extends Pet{
36
37 public void eat(){
38
39 System.out.println("兔子爱吃萝卜");
40
41 }
42
43}
44
45public class Dog extends Pet{
46
47 public void eat(){
48
49 System.out.println("狗爱啃骨头");
50
51 }
52
53}
54
55public class MasterTest {
56
57 public static void main(String[] args) {
58
59
60 Master master = new Master();
61
62 master.feed(new Cat());
63
64 }
65
66}
一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
抽象类是java中最顶级的一种表现形式,接下来就是类,再接下来就是对象
抽象类用abstract修饰 > 类class > new 对象
我们如果想创建对象的话,只能通过类class去创建,抽象类是不能创建对象的
因为抽象类的下一级是类
格式:abstract class 类名{}
xxxxxxxxxx
411public abstract class Animal{
2
3 private String name;
4
5 private static int age;
6
7 //定义抽象方法,抽象方法是没有方法体的
8 //为什么抽象类没有方法体?因为抽象方法本身就是模糊的,不用去提供具体的实现
9 public abstract String eat();
10
11 public void move(){
12
13 System.out.println("动物会移动")
14
15 }
16
17
18}
19
20public class Cat extends Animal{
21
22
23 public String eat(){
24
25 return "猫喜欢吃鱼";
26
27 }
28
29}
30
31public class AbstractTest01{
32
33 public static void main(String[] args){
34
35 Animal animal = new Cat();
36
37 System.out.println(animal.eat());
38
39 }
40
41}
抽象类中是有构造方法的(抽象类不可以实例化对象,但是却存在构造函数)
抽象类父类构造函数是通过子类构造去调用的,通过super关键字调用父类构造
xxxxxxxxxx
101public class Cat extends Animal{
2
3
4 public Cat(String name,int age){
5
6 super(name,age);
7
8 }
9
10}
final关键字:可以修饰类,成员变量,局部变量,方法(静态方法,实例方法)
用final关键字能不能修饰抽象类?不可以,因为抽象类的作用就是用来被子类继承的,但是被final修饰的类是无法被子类继承的,final和abstract是不能同时出现的
如何去声明一个常量?
常量是程序运行过程中不可以发生改变的量
对于那些无论创建多少次对象,值都亘古不变的数据,我们把该属性定义为常量
xxxxxxxxxx
11public static final 属性类型 常量名称(所有字母都大写,单词之间用_分隔) = 值
用static修饰常量是因为想让改常量变成一个类级别的,然后随着类加载,该常量就初始化
避免多次开辟空间,浪费系统资源
用final修饰常量,是因为不希望在程序运行时,该量的值发生变化,final代表最终的
接口:接口是一种规范,在进行程序设计的时候,都是基于接口进行开发
因为在声明方法的时候,我们需要这个方法存在多变性,而且可以随着业务的改变,针对这个接口做具体的实现
构造方法:没有,因为接口主要是扩展功能的,而没有具体存在
接口的定义:
格式: interface 接口名 {}
xxxxxxxxxx
211package com.os467.interface_test;
2
3//声明一个接口
4public interface MyInterface01{
5
6 int I = 100;
7
8 Object O = new Object();
9
10 static String ADDRESS = "南京"
11 //以上都是常量,忽略了public static final,不是变量
12
13 public static final String NAME = "Tom";
14 //可以省略public static final
15
16 //抽象方法
17 //public abstract void getMethod();接口中下面的代码等同于这行代码
18 void getMethod();
19
20
21}
接口在开发中的作用:
设计模式中提到在设计程序时,我们要面向接口开发,接口+多态,可以实现程序的可拓展性,灵活性
作用:子类实现接口的关键字(类似extends关键字)
接口中定义的抽象方法,在子类实现之后一定要进行重写
格式: class 类名 implements 接口名{}
xxxxxxxxxx
241public class MyInterfaceImpl implements MyInterface01{
2
3
4 public void getMethod(){
5
6 System.out.println("子类实现接口之后重写的方法")
7
8
9 }
10
11}
12
13public class InterfaceTest01{
14
15 public static void main(String[] args){
16
17 //通过多态的方式来创建实例
18 MyInterface01 myInterface01 = new MyInterfaceImpl();
19
20 myInterface01.getMethod();
21
22 }
23
24}
接口案例
xxxxxxxxxx
691package com.os467.interfaceTest.person;
2
3public interface Message {
4
5 void getMessage();
6
7}
8--------------------------------------------------------
9package com.os467.interfaceTest.person;
10
11public class QQ implements Message{
12
13
14 public void getMessage() {
15 System.out.println("接收的是QQ消息");
16 }
17}
18--------------------------------------------------------
19package com.os467.interfaceTest.person;
20
21public class Email implements Message{
22
23
24 public void getMessage() {
25
26 System.out.println("接收的是电子邮件");
27 }
28}
29---------------------------------------------------------
30 package com.os467.interfaceTest.person;
31
32public class QQ implements Message{
33
34
35 public void getMessage() {
36 System.out.println("接收的是QQ消息");
37 }
38}
39---------------------------------------------------------
40 package com.os467.interfaceTest.person;
41
42public class Person {
43
44 //接收消息的方法
45 public void receive(Message message){
46
47 //调用接收消息的方法
48 message.getMessage();
49
50 }
51
52}
53----------------------------------------------------------
54 package com.os467.interfaceTest.person;
55
56public class Test {
57
58 public static void main(String[] args) {
59
60 Person person = new Person();
61
62 //调用接收消息的方法
63 person.receive(new QQ());
64 person.receive(new WeChat());
65 person.receive(new Email());
66
67 }
68
69}
按照多态的方式,由具体的子类实例化,这其实也是多态的一种,接口多态
类对多个接口方法的实现
xxxxxxxxxx
131//一个类的多接口实现,接口与接口之间用逗号隔开
2public class MyImpl implements MyInterface01, Myinterface02{
3
4 public void getMethod(){
5
6 }
7
8
9 public String getMethod02(){
10
11 return null;
12 }
13}
接口与接口之间的多继承
xxxxxxxxxx
41//继承接口02,接口01的所有抽象方法与常量
2public interface MyInterface03 extends MyInterface02, MyInterface01(){
3
4}
总结:抽象类与接口的区别:
抽象类有成员变量,以及抽象方法(没有方法体)与普通方法,拥有自己的构造函数,继承抽象类的子类需要重写抽象类中的所有抽象方法,抽象类没有实例对象,因为其下一级是类
抽象类被继承体现的是”is a“的关系,共性功能
接口可以说是特殊的抽象类,只是接口内只有抽象方法和常量,接口不具有构造函数,实现接口的类需要重写接口中的所有抽象方法,接口没有实例对象,它的作用是用来被子类实现的
接口被实现体现的是:”like a“的关系,扩展功能
类与类:
继承关系,只能单继承,但是可以多层继承
类与接口:
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口与接口之间:
继承关系,可以单继承,也可以多继承
接口和抽象类都可以作为一个方法的返回值,参数,也可以作为类的成员变量
xxxxxxxxxx
81 public static void main(String[] args) {
2
3 public Myinterface02 getFun(){
4
5 //返回的是一个接口
6 return new MyImpl();
7
8 }
package只能存在工程的第一行
包其实就是文件夹
作用:对类进行分类管理
格式:package 包名;
多级包用”.“分开即可
访问权限修饰符区别
访问权限修饰符 | 本类 | 同一包下 | 子类(同一包下) | 子类(不同包下) | 不同包下非子类 |
---|---|---|---|---|---|
private | √ | × | × | × | × |
default(不写修饰符) | √ | √ | √ | × | × |
protected | √ | √ | √ | √ | × |
public | √ | √ | √ | √ | √ |
把类定义在其他类的内部,这个类就被称为内部类
内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有
外部类要访问内部类的成员,必须创建对象
xxxxxxxxxx
51//创建内部类的实例,B是类A的内部类
2A.B b = new A().new B();
3
4//调用内部类中实例的方法
5b.getMethod();
内部类中不允许写静态方法
就是内部类的简化写法
前提:存在一个类或接口
这里的类可以是具体类也可以是抽象类
格式:
new 类名或者接口名( ){重写方法;}
本质:
创建一个父类所对应的匿名对象
是一个继承了
类或者实现了接口的子类匿名对象
xxxxxxxxxx
151//给接口创建一个匿名对象,可以把 new MyInterface(){}视为接口的匿名子类
2MyInterface myInterface = new MyInterface(){
3
4
5 public double getSum(double num1, double num2){
6
7 return num1 + num2;
8 }
9
10};
11
12double sum = myInterface.getSum(100,200);
13
14System.out.println("结果为"+sum);
15//结果为 300.0
当程序出现异常时,java会创建对应的异常对象,并且抛出(throw)
当异常抛出之后,会影响接下来代码的执行(打断)
在 Java 中,所有的异常都有一个共同的祖先类Throwable(可抛出)
Throwable有两个子类 Error 和 Exception
错误(Error): JVM系统内部错误,资源耗尽等严重情况
Error是Throwable的子类,用于指示合理的应用程序不应该试图捕获的严重问题
无法从代码层面解决此异常
异常(Exception): 其它因编程错误或偶然的外在因素导致的一般性问题
Exception(异常):是程序本身可以处理的异常,Exception 类有一个重要的子类RuntimeException
常见异常:
RuntimeException
ArithmeticException:数学计算异常
NullPointerException:空指针异常
NegativeArraySizeException:数组索引越界异常
ClassNotFoundException:类文件未找到异常
ClassCastException:造型异常
IOException
FileNotFoundException:文件未找到异常
EOFException:读写文件尾异常
异常:
编译时异常:当JVM进行编译的时候就会出现报错,对于那些大概率会发生的异常,我们会定义成编译时异常,编译时异常要求开发人员必须对其进行处理
直接或间接继承了Exception类的异常就是编译时异常
运行时异常:程序在运行时,才会出现的异常,小概率会出现的异常,我们会定义成运行时异常,开发人员可以不用对其进行处理
直接或者是间接的继承了RuntimeException
类,该异常就是运行时异常
1.通过throws关键字将异常往上抛
xxxxxxxxxx
91//throws关键字为方法添加方法体内可能出现的异常,如文件找不到异常,不添加则无法运行方法体中的代码
2public static void main(String[] args) throws FileNotFoundException {
3
4 FileInputStream fileInputStream = new FileInputStream("D:\\test\\test.txt");
5
6 System.out.println(fileInputStream);
7
8
9 }
2.通过异常的捕获try{}catch{}语句块
语句块机制:
xxxxxxxxxx
151try{
2 //可能会抛出特定异常的代码段
3}catch(MyExceptionType myException){
4 //如果myException被抛出,则执行这段代码
5}catch(Exception otherException){
6 //如果另外的异常otherException被抛出,则执行这段代码
7}finally{
8 //用于资源回收,回收的资源一般是指会造成对系统资源浪费的对象
9 //无条件执行的语句!!一定会执行
10}
11/*
12通过这种方式去处理异常,在捕获到异常之后,还是一样会创建该异常对象,但是该对象会
13被catch语句块所捕获,具体用异常类来接收该异常对象,然后在catch语句块中可以针对
14该异常进行相关的处理,程序会继续往下执行
15*/
注意:用try{…}catch{…}捕捉了异常之后一定要对在catch{…}中对其进行处理,那怕是最简单的一句输出语句,或打印日志来显示整个调用流程
xxxxxxxxxx
61catch(Exception e){
2
3 //栈输入,打印日志
4 e.printStackTrace();
5
6}
throws : 是方法可能抛出异常的声明
用在声明方法时,表示该方法可能要抛出异常,交给上层调用它的方法程序处理
通过throws关键字(写在方法后面的)把异常向上抛(抛给该方法的调用处)
不会影响程序正常运行
xxxxxxxxxx
111//throws后面为方法中可能出现的异常,如空指针异常
2public void getMethod01() throws NullPointerException{
3
4}
5
6//抛出编译时异常
7public FileInputStream getMethod02() throws FileNotFoundException{
8
9 return new FileInputStream("D:\\file\\demo.java")
10
11}
java给我们提供了很多种异常,但是在做项目的时候,这些异常是不够用的,所以需要我们自定义异常
自定义异常方式:
RuntimeException
xxxxxxxxxx
211public class ExceptionDemmo extends Exception{
2
3 //提供一个构造,把异常信息告诉父类
4 public ExceptionDemmo(String message){
5
6 super(message);
7
8 }
9
10}
11
12public class RuntimeExceptionDemmo extends RuntimeException{
13
14 //提供一个构造,把异常信息告诉父类
15 public RuntimeExceptionDemmo(String message){
16
17 super(message);
18
19 }
20
21}
系统在遇到异常时会自动生成一个 throw new 异常类(); 来抛出异常
throw是语句抛出一个异常,一般是在方法体的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常
xxxxxxxxxx
171public static void main(String[] args) throws Exception{
2
3 ExceptionDemo exceptionDemo = new ExceptionDemo("这是我提供的自定义异常信息");
4
5 throw exceptionDemo;
6
7 //也可写成throw new ExceptionDemmo("这是我提供的自定义异常信息");
8}
9
10public static void main(String[] args){
11
12 RuntimeExceptionDemo runtimeExceptionDemo = new RuntimeExceptionDemo("这是我提供的自定义异常信息");
13
14 throw exceptionDemo;
15
16 //也可写成throw new RuntimeExceptionDemmo("这是我提供的自定义异常信息");
17}
字符串比较的方法:
空指针异常时以后我们写程序经常会遇见的一种异常,接收过来的引用为空,然后拿着该引用去调用方法
空指针异常的解决方案:我们要对接收过来的引用数据类型做非空校验
xxxxxxxxxx
191public boolean getEquals(String str1, String str2){
2
3 boolean b = false;
4
5 if (str1 == null || str == null){
6
7 System.out.println("接收的引用为空")
8
9 }else{
10
11 b = str1.equals(str2);//new NullPointerException();
12
13 return b;
14
15 }
16
17 return b;
18
19}
集合:
java中所有的基本数据类型都有对应的封装类(引用数据类型),我们学习的集合是只能存放引用数据类型的容器。
xxxxxxxxxx
141int i = 100;
2
3//创建一个集合对象
4ArrayList arrayList = new ArrayList();
5
6//添加元素的方法,自动装箱:int ---> Integer
7arrayList.add(i);
8
9for (int j = 0; j < arrayList.size(); j++){
10
11 //根据下标来取元素
12 System.out.println(arrayList.get(j));
13
14}
Java中有自动装箱机制,会把基本类型转化为其对应的封装类:
将引用数据类型转为基本数据类型就是自动拆箱
Iterator接口:Collection继承的超级接口, 只有一个返回迭代器的方法
Collection : 集合层次中的根接口,JDK没有提供这个接口直接的实现类
将一组对象以集合元素的形式组织到一起,在其子接口中分别实现不同的组织方法
xxxxxxxxxx
541//创建一个集合对象
2Collection collection = new ArrayList();
3
4//添加的是基本数据类型 会自动装箱
5collection.add(1000);
6
7//添加浮点型 自动装箱
8collection.add(3.14);
9
10//添加引用数据类型
11collection.add(new Object());
12
13System.out.println("集合的长度为"+collection.size());
14
15//遍历Collection接口方法 遍历集合中的元素
16//获取迭代器对象方法
17Iterator iterator = collection.iterator();
18while (iterator.hasNext()){
19
20 Object next = iterator.next();
21
22 System.out.println(next);
23
24}
25
26//判断集合中是否包含指定元素
27System.out.println("是否包含元素?"collection.contains(1000));
28
29//比较集合是否相等
30System.out.println(collection.equals(collection1));
31
32//返回哈希码值
33System.out.println("hash码值为"+collection.hashCode());
34
35//判断集合是否为空
36System.out.println("集合是否为空?"+collection.isEmpty());
37
38//根据指定元素,删除集合中所对应的元素
39collection.remove(1000);
40
41//返回集合元素个数
42System.out.println("集合元素个数:"+collection.size());
43
44//将集合转成数组
45Object[] objects = collection.toArray();
46
47for (Object object : objects){
48
49 System.out.println(object)
50
51}
52
53//清空集合中的元素
54collection.clear();
Collection的两个子接口:
是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式
xxxxxxxxxx
241public class CollectionTest01 {
2
3 public static void main(String[] args) {
4
5 List list1 = new ArrayList();
6
7 List list2 = new Vector();
8
9 list1.add(100);
10 list1.add(100);
11 list1.add("hello");
12 list1.add(new Object());
13 list1.add(list2);
14
15 //List接口提供按索引访问的方法
16 for (int i = 0; i < list1.size(); i++) {
17
18 System.out.println(list1.get(i));
19
20 }
21
22 }
23
24}
迭代器方法访问元素:
Iterator接口定义了对Collection类型对象中所含元素的遍历等增强处理功能
可以通过Collection接口中定义的iterator()方法
获得一个对应的Iterator(实现类)对象
Set(实现类)对象对应的Iterator仍然是无序的
List(实现类)对象对应的ListIterator
对象可以实现对所含元素的双向遍历:
使用next()方法和previous()方法
xxxxxxxxxx
191 //获取迭代器对象,注意:获取迭代器对象之后不允许对集合元素进行修改或删除,否则会报错
2 Iterator iterator = list1.iterator();
3
4 /*遍历集合
5 iterator.hasNext()是一个指针,判断集合中下一个
6 单元中是否存在元素,如果存在指针向下走一个单元*/
7 while(iterator.hasNext()){
8
9 //返回当前指针指向的元素
10 Object next = iterator.next();
11
12 //迭代器的删除方法,删除的是当前遍历的元素
13 //iterator.remove();
14
15 //最好不要在迭代器中用
16 //List.remove(next)
17
18 System.out.println(next);
19 }
forEach循环(加强版for循环):
xxxxxxxxxx
51for (Object obj : list1){
2
3 System.out.println(obj);
4
5 }
案例分析(关于集合当中的方法):
List的方法:
contains 方法: 底层重写了equals方法,判断集合中是否包含某一个元素,如果该元素重写了equals方法,比较的就是内容,如果没有重写equals方法,默认会采用Object类中的equals方法,这时候比较的就是地址
remove方法: 底层重写了equals方法,删除集合中的元素,但是永远只能删除一个元素,因为在底层删除之后就return了
xxxxxxxxxx
231/**
2 * 创建两个学生对象(属性有 姓名,年龄,身份证号),然后
3 * 重写equals方法,在年龄姓名身份证号相同的清空下,两个比较的实例才是相同的!
4 *
5 */
6public class ListDemo {
7 public static void main(String[] args) {
8
9 //创建集合对象
10 List list = new ArrayList();
11
12 //创建两个学生实例
13 Student student1 = new Student("Tom",20,"1232312312");
14 Student student2 = new Student("Tom",20,"1232312312");
15
16 list.add(student1);
17
18 //因为在contains的底层调用了equals方法,student在contains中用Object类接收
19 //而父类Object中的equals方法不能满足需求,因此需要在Student类中去重写equals方法
20 System.out.println(list.contains(student2));
21 }
22
23}
xxxxxxxxxx
761public class Student {
2
3 private String name;
4
5 private int age;
6
7 private String idCard;
8
9 public Student(String name, int age, String idCard) {
10 this.name = name;
11 this.age = age;
12 this.idCard = idCard;
13 }
14
15 public Student() {
16 }
17
18 public String getName() {
19 return name;
20 }
21
22 public void setName(String name) {
23 this.name = name;
24 }
25
26 public int getAge() {
27 return age;
28 }
29
30 public void setAge(int age) {
31 this.age = age;
32 }
33
34 public String getIdCard() {
35 return idCard;
36 }
37
38 public void setIdCard(String idCard) {
39 this.idCard = idCard;
40 }
41
42 //重写equals方法
43
44 public boolean equals(Object obj) {
45
46 //如果接收到为空 或者 obj不是Student类的对象 返回false
47 if (obj == null || !(obj instanceof Student)){
48
49 return false;
50
51 }
52
53 //对obj向下转型,用Student类的对象student接收
54 Student student = (Student)obj;
55
56 //满足 对象与student的姓名,年龄,身份证号相等 返回true
57 if(this.name.equals(student.name) && this.age == student.age && this.idCard.equals(student.idCard)){
58
59 return true;
60
61 }
62
63 //不满足则返回false
64 return false;
65 }
66
67
68 public String toString() {
69 return "Student{" +
70 "name='" + name + '\'' +
71 ", age=" + age +
72 ", idCard='" + idCard + '\'' +
73 '}';
74 }
75}
76
ArrayList
和 vector
集合区别:
这两个集合底层都封装了数组这一种数据结构,ArrayList
是线程不安全的,Vector
是线程安全的
所有封装的方法都是一样的,还有就是扩容机制有一点不一样,ArrayList
和 vector
最开始的时候只能存放10个元素,默认初始容量是10,当元素超过10个之后,就会触发底层的扩容机制
ArrayList
的扩容因子是1.5 10 * 1.5 = 15
Vector
的扩容因子是2.0 10 * 2.0 = 20
ArrayList
和 LinkedList
集合区别:
ArrayList
底层是数组,LinkedList
底层是链表结构
数组查询效率高,随机增删效率低
链表随机增删效率高,查询效率低
JDK1.5版本之后引入的新特性,强制让集合只能存放某一种数据类型
<数据类型>钻石表达式
xxxxxxxxxx
21//创建只能存放字符串类型的数组
2ArrayList<String> string = new ArrayList<>();
自定义泛型:
xxxxxxxxxx
281//<>内部的类容可以是任意的,例如可以是Collection<? extends E> var1,即传入数据类型必须是Collection的子类
2//<E>的存在用来接收Person类内部的E的具体引用数据类型
3public class Person<E> {
4
5 //e这个成员变量的类型为E,E的类型由外部指定
6 private E e;
7
8 //泛型构造方法形参e的类型也为E,E的类型由外部指定
9 public void getE(E e){
10
11 System.out.println(e);
12
13 }
14
15}
16
17------------------------------------------------------------
18public class Test {
19
20 public static void main(String[] args) {
21
22 Person<String> stringPerson = new Person<>();
23
24 stringPerson.getE("abc");
25
26 }
27
28}
Set接口的实现类:HashSet
底层封装了HashMap
HashSet
中不允许出现重复元素,不保证集合中元素的顺序(存入的顺序与取出的不同)
HashSet
中允许包含值为null的元素,但最多只能由一个null元素
xxxxxxxxxx
131 HashSet<String> hashSet = new HashSet<>();
2
3 hashSet.add("abc");
4 hashSet.add("efg");
5 hashSet.add("xyz");
6 hashSet.add("xyz");
7
8 for (String s : hashSet) {
9
10 System.out.println(s);
11
12 }
13
Set接口的实现类:TreeSet
底层封装了TreeMap
xxxxxxxxxx
141//创建TreeSet集合
2TreeSet treeSet = new TreeSet();
3
4 treeSet.add(123);
5 treeSet.add(124);
6 treeSet.add(120);
7 treeSet.add(128);
8 treeSet.add(129);
9
10 for (Object o : treeSet) {
11
12 System.out.println(o);
13
14 }
map集合是存放键值对的容器
value是key的一个替代品,我们以后操作元素时,是根据key去操作
map集合的key是不允许重复的,如果在添加元素时,key的值重复,那么后添加的元素将会把前一个覆盖掉
value的值可以重复
Map:包含了key-value对, Map不能包含重复的key, SortedMap
是一个按照升序排列key的Map
映射(map)是一个存储关键字和值的关联或者说是关键字/值对的对象,给定一个关键字,可以得到它的值
关键字和值都是对象,关键字必须是唯一的,但值是可以被复制的
有些映射可以接收null关键字和null值,而有的则不行
xxxxxxxxxx
511//创建集合对象
2Map map = new HashMap();
3Map map2 = new HashMap();
4
5//添加元素
6map.put("name","jack");
7map.put("age",20);
8map.put("address","北京市");
9map.put("idCard","123456");
10
11//查看集合的长度
12System.out.println("集合的长度为"+map.size());
13
14//查询集合中是否包含某一个key
15System.out.println("是否包含key"+map.containsKey("name"));
16
17//是否包含value
18System.out.println("是否包含value"+map.containsValue(20));
19
20//判断集合对象是否相等
21System.out.println(map.equals(map2));
22
23//根据key来获取value
24System.out.println("name的值为"+map.get("name"));
25
26//判断集合是否为空
27System.out.println("是否为空"+map.isEmpty);
28
29//将map集合中的key部分转成set集合
30Set set = map.keySet();
31
32for(Object o : set){
33
34 System.out.println(o);
35
36}
37
38//复制集合中所有的元素,将map的内容复制给map2
39map2.putAll(map);
40
41//根据key来删除整个键值,返回的是删除的key所对应的value
42Object age = map.remove("age");
43
44//将map集合所有的value部分转成collection集合
45Collection collection = map.values();
46
47for(Object o : collection){
48
49 System.out.println(o);
50
51}
如何遍历Map集合(两种方法):
1.keySet方法:将map集合所有key部分转成set集合,再根据get()获取对应value的值
xxxxxxxxxx
251//创建map集合对象
2Map map = new HashMap();
3
4//添加元素
5map.put("name","Tom");
6map.put("age",20);
7map.put("address","北京市");
8map.put("idCard","123456");
9
10//将所有的key转成set集合
11Set set = map.keySet();
12
13//获取迭代器对象
14Iterator iterator = set.iterator();
15
16while (iterator.hasNext()){
17
18 Object key = iterator.next();
19
20 //根据key获取value
21 Object value = map.get(key);
22
23 System.out.println(key+" = "+value);
24
25}
2.Set<Map.Entry<K,V> entrySet()
将map集合转成set集合(效率比第一种高)
xxxxxxxxxx
141Set<Map.Entry<String,String>> entries = map.entrySet();
2
3//这里的Entry<k,V>为Map的内部接口
4for (Map.Entry<String,String> entry : entries){
5
6 //获取key的值
7 String key = entry.getKey();
8
9 //获取value的值
10 String value = entry.getValue();
11
12 System.out.println(key+" = "+value);
13
14}
Map接口实现类:HashMap
:
hashMap
集合的存储过程:
hashCode()
随机生成哈希码值
我们添加到集合的元素是引用数据类型
那一定会继承Object类中的hashCode
方法
首先map集合会调用put()方法来添加元素,
这个时候hashMap
底层会生成hash值(如果在该引用数据类型中重写了hashCode方法,那么生成的不再是随机值,数据便会存储在同一单元中)
根据这个hash值来计算该元素的位置应该存放在数组的哪个单元下面
确定了存放的单元,这个时候就会去拿着key的引用
与该单元下所有的node节点进行一个equals比较(该引用数据类型有没有重写equals方法如果重写了,比较的是对应属性的内容,如果没有重写,那比较的就是内存地址)
如果发下equals的返回值是true,新添加进来的节点将会把旧的节点覆盖掉
如果equals的返回值是false,该节点将会存放在数组单元中的单向链表的最下面(成为链表尾节点)
xxxxxxxxxx
61//创建集合对象
2HashMap<Student,Object> hashMap = new HashMap<>();
3
4//添加元素,key和value
5hashMap.put(new Student("jack",20),100);
6hashMap.put(new Student("jack",20),101);
hashMap
案例:
xxxxxxxxxx
321//根据hashMap统计字符出现的个数
2String str = "djaiwj jdjia1dj dj";
3
4 char[] chars = str.toCharArray();
5
6 //创建hashMap集合
7 HashMap<Character,Integer> hashMap = new HashMap<>();
8
9 for (char aChar : chars) {
10
11 //在遍历字符数组的过程中判断map集合中是否有该字符,如果有在当前个数基础上加一
12 //如果不存在,则把该字符重新添加到集合中,个数赋值为1
13 if (hashMap.containsKey(aChar)){
14
15 //个数在当前基础上加一
16 hashMap.put(aChar,hashMap.get(aChar)+1);
17
18 }else{
19
20 hashMap.put(aChar,1);
21
22 }
23
24 }
25
26 //遍历map集合
27 Set<Map.Entry<Character, Integer>> entries = hashMap.entrySet();
28
29 for (Map.Entry<Character, Integer> entry : entries) {
30
31 System.out.println(entry.getKey()+"===>"+entry.getValue());
32 }
Map接口实现类:HashTable
:
HashTable
和HashMap
的区别:
HashMap
key-value可以为一次空
HashTable
不可以为空
HashTable
是线程同步的,也是线程安全的
其实hashtable
就是线程安全版的hashmap
,所有的方法以及使用方式都是一样的
hashtable
的key和value不允许为空
跟arrayList
和vector
是一样的,hashmap
的执行效率要比hashtable
高,因为hashtable
所有的方法都添加了线程同步关键字,这样的话在多线程场景下,执行效率是不高,但是以后开发中我们可以通过别的途径来解决线程安全问题,所以hashMap
这个集合是我们以后使用的最多key-value集合
xxxxxxxxxx
11Hashtable<Object,Object> hashtable = new Hashtable<>();
Map接口实现类:TreeMap
:
treeMap
是一个可以按照key自动排序的集合
xxxxxxxxxx
361//创建集合对象
2Treemap<Integer,Object> treeMap = new TreeMap<>();
3
4treeMap.put(110,101);
5treeMap.put(100,101);
6treeMap.put(102,101);
7
8//map集合转set集合
9Set<Map.Entry<String,String>> entries = treeMap.entrySet();
10
11//forEach
12for (Map.Entry<Integer, Object> entry : entries){
13
14 System.out.println(entry.getKey()+" = "+entry.getValue());
15
16}
17//输出结果:
18//100 = 101
19//102 = 101
20//110 = 101
21
22//对自定义的引用数据类型使用treeMap,treeSet需要在类中实现Comparatable接口
23public class Goods implements Comparable<Goods> {
24
25 private Double price;
26
27 //重写compareTo方法,二叉树根据返回的值的正负来存放数据
28
29public int compareTo(Goods goods){
30
31 return (int)(this.price - goods.price);
32
33}
34
35}
36
案例:
用hashMap
统计字符出现的个数
xxxxxxxxxx
671package com.os467.hashMapDemo;
2
3import java.util.HashMap;
4import java.util.Map;
5import java.util.Set;
6
7public class HashMapTest {
8
9 public static void main(String[] args) {
10
11 //统计每个字符出现的次数
12 getCharNum();
13
14 }
15
16 /**统计字符出现的个数
17 *s.matches()正则表达式方法,用于匹配符合规则的字符串
18 */
19 public static void getCharNum(){
20
21 System.out.println("---------统计每个字符出现的次数----------");
22
23 //创建HashMap集合
24 HashMap<Character,Integer> hashMap = new HashMap<>();
25
26 //将字符串切割成字符数组
27 char[] chars = getString().toCharArray();
28
29 //遍历字符串数组
30 for (char c: chars) {
31
32 if (hashMap.containsKey(c)) {
33
34 //个数在当前基础上加一
35 hashMap.put(c, hashMap.get(c) + 1);
36
37 } else {
38
39 hashMap.put(c, 1);
40
41 }
42
43 }
44 //将map集合转成set集合
45 Set<Map.Entry<Character, Integer>> entries = hashMap.entrySet();
46
47 //遍历set集合
48 for (Map.Entry<Character, Integer> entry : entries) {
49
50 System.out.println(entry.getKey()+" ===> "+entry.getValue());
51
52 }
53
54
55
56
57 }
58
59 //获取字符串的方法
60 public static String getString(){
61
62 return "adaw diicj123";
63
64 }
65
66}
67
Properties集合:
继承了hashtable
xxxxxxxxxx
261 //创建集合对象
2 Properties properties = new Properties();
3
4 //创建流对象
5 FileReader fileReader = new FileReader("jdbc");
6
7 //通过流对象去解析数据,并把数据放到集合
8 properties.load(fileReader);
9
10 //私有的方法
11 properties.setProperty("username","root");
12 properties.setProperty("password","root");
13 properties.setProperty("url","jdbc:mysql://localhost:3306");
14 properties.setProperty("driver","com.mysql.jdbc.driver");
15
16 //取出集合中的数据
17 String username = properties.getProperty("username");
18 String password = properties.getProperty("password");
19 String url = properties.getProperty("url");
20 String driver = properties.getProperty("driver");
21
22 System.out.println(username);
23 System.out.println(password);
24 System.out.println(url);
25 System.out.println(driver);
26
Collection体系:
List接口:
ArrayList
:
有序可重复的集合,底层封装了数组这种数据结构,所以有数组所有的特性,可以通过下标索引来获取元素,查询数据的效率会很高,但是随机增删的效率会比较低,本身是一个线程不安全的集合,默认初始容量是10,如果存放元素超过10会触发扩容机制,扩容因子是1.5,每触发一次扩容机制,加载为原来的1.5倍
Vector
:
Vector就是一个线程安全版的Arraylist
,这个集合的所有方法都添加了线程同步关键字,在多线程场景下,效率是很低的,我们一般不会使用这个集合,默认初始容量是10,如果存放元素超过10会触发扩容机制,扩容因子是2.0,每触发一次扩容机制,加载为原来的2倍
LinkedList
:
这个集合在底层封装了单向链表这种数据结构,所以该集合拥有链表的所有特性,查询效率是不高的,但是随机增删效率很高,而且在LinkedList
底层还为我们封装了队列,我们可以去调用入队和出队的方法
Set接口:
HashSet
:
在底层为我们聚合了HashMap
,在添加元素的时候,实际上调用了HashMap
的put方法,元素存放在put方法的key部分
HashSet
是一个无序不可重复的集合,存入数据的顺序和取出数据的顺序是不同的
TreeSet
:
在底层为我们聚合了TreeMap
,在添加元素的时候,实际上调用了TreeMap
的put方法,元素存放在put方法的key部分
TreeSet
是一个可以按照排序规则自动排序的方法,如果存入元素的引用时我们自定义的,该引用必须要实现比较器接口Comparable<泛型>,重写比较规则,不然会报类型转换异常
Map体系:
HashMap
:
可以以key-value的形式去存放数据,key和value都是允许为空的,不是线程安全的集合,但是执行效率很高,在底层封装的是哈希散列
HashTable
:
线程安全版的HashMap
,执行效率不是很高,key和value都不允许重复
TreeMap
:
是可以根据key来完成自动排序的key-value集合,如果存入元素的引用是我们自定义的,该引用必须要实现比较器接口Comparable<泛型>,重写比较规则,不然会报类型转换异常
Properties
:
这个集合继承了HashTable
,所以该集合是一个线程安全的集合,而且提供了私有的方法SetProper()
,getProper()
,该集合可以集合流对象高效的去读取配置文件,把数据解析到集合中