一、基本语言与数据类型
1. idea常用方法快捷键
main方法:输入psvm然后回车
System.out.println():输入sout然后回车
fori/sout/psvm + Tab
ctrl+shift+方向箭:将光标所在代码块整体向上或者向下移动
alt+shift+方向键 :将所在行向上或者向下移动
ctrl+/:行注释
ctrl+shift+/ :块注释
ctrl+alt+I:自动缩进
- 变量特点
1.占据着内存中某一块存储区域
2.该区域有自己的名称(变量名)和类型(数据类型)
3.可以被重复使用
4.该区域的数据可以在同一类型f范围内不断变化
- 标识符与命名特点
1.由字母、数字、下划线、$符组成,不能以数字开头(字母可以是中文)
2.区分大小写
3.不得使用java中的关键字和保留字
4.不用java中内置的类名作为自己的类名
- 注释
1.单行注释://
2.多行注释:/* */
3.文档注释:
- 数据类型分类
1.基本数据类型
数值型
byte(1B) short(2B) int(4B) long(8B)
float(4B) double(8B)
字符型
char(2B)
布尔型
boolean(1bit)
2.引用数据类型
类、接口、数组
- 整数与浮点数
1.整数默认为int类型,声明long变量后加上‘l’或者'L'
2.小数默认为double类型,声明float变量时需在后面加f或者F
- 强制类型转换
short i=(short)s;
- 自动类型提升
//小的数据类型和大的数据类型运算时会自动提升为大的数据类型
int t=20+s;//自动提升为int
##二、 运算符
- 字符串相加
String s1="ds";
String s2="dfx";
String s=s1+s2;
- 除法
//当两个整数在使用除号操作时,得到的结果为小数时,小数部分可以忽略,结果仍然为整数
System.out.println(3/5);//结果为0.6,但小数部分被省略所以为0
//如果想要两个整数相除为小数,则需要强制类型转换为float
System.out.println((float)3/5)
- 取模
其结果的符号与左边运算数的符号相同
- 赋值运算符
=、/=、+=、-=、*=
short s=3;
//s=s+3;//这样将报错,因为自动类型提升将提升为int类型
//s=(short)(s+3);//这样将正确
s+=3;//不报错的原因是其内部自动帮我们进行了上面的强制类型转换
- 比较运算符
==、>=、<=、!=
- 逻辑运算符
与(&)、或(|)、非(!)、异或(^)、短路与(&&)、短路或(||)
异或:相同为false 不同为true
&:只要一个为假结果就为假,不论前面结果是真是假后面表达式都会执行
&&:只要发现为假时就不再往后执行
|:只要一个为真结果就为真
||:执行时只要发现结果为真就不再往后执行
- 位运算符
byte a=15;
byte b=-15;
System.out.println(a&b);
System.out.println(a|b);
System.out.println(a^b);
System.out.println(~a);
System.out.println(~b);
三、方法与数组
- 形参和实参
sum(4,5);//4 5 为实际参数
public void sum(int a,int b){}//a b为形式参数
- 方法重载
在同一个类中方法名称相同但参数不同
- 数组
一维数组:把相同数据类型有序的组成在一起,我们称这样的集合为数组
相同的数据类型、有序的组成在一起
一维数组初始化:
//静态初始化
int[] ages=new int[]{21,22,23};
int[] ages;
ages=new int[]{21,22,23};
//动态初始化
int[] ages=new int[20];
一维数组遍历:
for(int i=0;i<ages.length;i++)
{
System.out.println(ages[i]);
}
二维数组:
int[][] ages=new int[][]{{13,19,20,17},{19,19,20},{30,19}};
for(int i=0;i<ages.length;i++){
int[] array=ages[i];
for(int j=0;j<array.length;j++){
System.out.println(array[j]);
}
}
foreach:
for(int i:ages){
System.out.println(i);
}
方法的可变参数:
public void sum(int...a){
}
四、类与对象
- 面向对象三大特性
- JVM内存划分
JVM主要将内存划分为:方法去、栈、本地方法栈、堆、程序计数器
基本数据类型在堆中的初始值:
byte:0 short:0 int:0 long:0L
float:0.0f double:0.0d char:'/u0000'
boolean:false
五中引用类型:
类、接口、数组、枚举、注解
五、匿名对象与构造器
- 匿名对象
匿名对象:创建一个对象,没有把它赋值给任何一个变量。匿名对象只能使用一次
new Dog().name;
构造器:在创建对象时自动调用的方法,称为构造器。通过反编译器可以看到默认的构造 方法
b编译器编译原文件时,会创建一个缺省的构造器,如果设置了默认值,默认值也是在构造器当中设置的。
构造器作用:创建对象、完成对对象的初始化
构造器特点:构造器名称和当前类名相同;禁止有返回值即不能使用return
构造器重载:构造器名称相同,参数不同
成员变量与局部变量:
成员变量:直接定义在类中的变量
类成员变量(在成员变量前加static)、实例成员变量(在成员变量前没加static)
有初始值,没有初始化也会有默认初始值。
局部变量:定义在方法当中的变量(参数和内部定的变量、代码块)
使用前要进行初始化。
六、封装
- 访问修饰符
private:只能在本类访问,离开后就不能访问了。
protected:同包及不同包的继承的子类可访问
public:都可访问
默认:同包可访问
- this
使用:
1.帮我们区分成员变量和局部变量的二义性
2.在同类中实例方法的调用,前面其实是有this,可以省略
3.可以把this作为参数传递
4.可以当作返回值返回
5.static不能和thi一起使用
6.this();此时this代表是构造器名,必须写在第一行
七、继承
- 方法的覆盖
方法的覆盖:子类重新定义父类中方法的过程
原则:
1.覆盖的方法名必须和父类方法名相同
2.覆盖方法的返回值 类型必须和父类相同
3.覆盖方法访问权限必须比父类方法大或者一样大。
@Override//判断该方法是否为覆盖方法
void fly(){
}
super();this()构造方法必须放在第一行
this.字段或者方法:先到本类当中去找指定的内容,如果没有,再去父类当中找,如果父类有再看父类允不允许继承,如果允许就使用父类的。
八、代码块与final关键字
- 代码块
代码块:
在类中或者方法当中 使用{}括起来的一段代码
1.局部代码块:
直接定义在方法内部的代码块
2.初始化代码块:
直接在类当中定义的代码块。没创建一个对象就会执行一次
3.静态代码块:在初始化代码块前面加static。在加载字节码时就会自动调用。在主方法之前执行,且只执行一次。
4.类什么时候加载:当第一次使用该类对象时,去加载到JVM中
5.字段初始化:
静态字段初始化:在静态代码块当中初始化
非静态字段初始化:在构造器当中初始化
6.子类构造器会默认调用父类构造器
7.final:最终,不可修改
可以修饰:
字段:不能再去修改该字段
方法:子类不能再覆盖该方法
类:不能被继承
final修饰字段时,字段没有初试值,必须自己手动设置初始值
final修饰变量 就代表是一个常量 所有字母都大写
final可以再局部代码块中使用
如果final修饰基本数据类型代表值不能再修改
final修饰引用数据类型代表地址不能再修改
九、包装类
1、装箱:
Integer num=new Integer(2);
Integer num2=Integer.valueOf(2);
2、拆箱
int num3=num.intValue();
3、自动装箱
Integer i=20;
4、自动拆箱
int i=num2;
5、字符串转换成包装类型
Integer i=new Integer("12");
6、包装类转换成字符串
String str=i.toString();
7、基本数据类型转字符串 直接再后面+“”
int a=10;
String str=a+"";
8、字符串转成基本数据类型
int i=Integer.parseInt(str);
9、valueOf缓存设计
Integer i1=new Integer(10);
Integer i2=new Integer(10);
System.out.println(i1==i2);//false
Integer i3=Integer.valueOf(10);
Integer i4=Integer.valueOf(10);
System.out.println(i3==i4);//true
十、抽象类与接口
- 抽象方法
在方法前面添加了一个关键字abstract
特点:
1.没有方法体
2.必须要定义在抽象类或者接口中
3.抽象方法不能是私有的 不能用final static修饰
- 抽象类
抽象类必须要有子类才行(抽象类一般被当作父类继承)
注意点:
1.抽象类不能直接创建对象
2.抽象类当中可以有抽象方法也可以有非抽象方法
3.子类没有覆盖抽象方法 可以把子类也编程抽象类
4.构造方法不能为私有(抽象类放法必须要有子类继承后,才能实现内部方法 子类继承 的话先去调用父类构造方法)
5.抽象类不能用final修饰
6.抽象类命名时,都喜欢在前面加Abstract
- 接口
定义:
interface 接口名{}
接口也会生成对应的字节码
接口其实是一个特殊的抽象类,内部的abstract可以省略不写
void transData();
public abstract void transData();
注意点:
接口没有构造器 所以不能创建对象
接口当中定义的变量都是全局静态常量:
String str="DD";
public static final str="DD";
接口当中定义的方法都是公共的抽象方法
void transData();
public abstract void transData();
十一、内部类与枚举
- 内部类
内部类:定义在类当中的一个类
为何使用内部类:
1.增强封装:把内部类隐藏在内部类当中,不允许其它类访问这个内部类
2.增加了代码一个维护性
3.内部类可以直接访问外部类当中的成员
内部类可以分为四种:
1.实例内部类:直接定义在类当中的一个内部类,类前面没有任何修饰符
2.静态内部类:在内部类前面加上static
3.局部内部类:定义在方法的内部类
4.匿名内部类:属于局部内部的一种特殊情况
实例内部类:
创建实例内部类:
Outter out=new Outter();
Outer.Inner inn=out.new Inner();
外部类访问不到内部类当中的成员
静态内部类:
静态内部类不需要创建外部类
静态类当中没有外部类的引用的
Outter.Inner inn=new Outter.Inner();
访问静态l类当中的静态成员
System.out.println(Outter.Inner.color)
静态内部类当中可以定义静态成员也可以定义非静态成员
局部内部类:
不能使用public private ...等修饰符
局部内部类只能定义在方法当中使用
局部内部类中是不能包含静态变量
局部内部类当中可以使用局部变量,使用的局部变量的 本质是final
匿名内部类:
就是一个没有名字的局部内部类
匿名内部类没有构造器
- 枚举
enum WeekDay{
MONDAY,TUESDAY,WENDSDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY
}
枚举是一个特殊的类
枚举不能直接创建对象,在编译时会把构造器私有化
字符串变枚举:
Sex S=Sex.valueOf("MAN");
switch(Sex.FEMALE){
case MAN:break;
case FEMALE:break;
}
Sex[] allsex=Sex.values();
for(Sex s:allsex){
System.out.println(s);
}
十二、常用类
- main
1.当点击运行时,JVMz自动会调用main方法
2.public:被JVM调用时它的权限要足够大
3.static:被JVM调用时,不需要创建对象,直接使用类名调用
4.void::被JVM调用的方法不需要有任何返回值
5.main:方法的名称 只能这样写不然JVM识别不了
6.String[] args:以前是指键盘输入
public static void main(String[] args){
for(String str:args){
System.out.println(str);
}
}
- Scanner
import java.util.Scanner;
Scanner scn=new Scanner(System.in);
int i=scn.nextInt();
double i2=scn.nextDouble();
- 数组拷贝
int[] src={1,2,3,4,5,6};
int[] desc=new int[10];
System.arraycopy(scr,2,desc,2,4);
System.out.println(Arrays.toString(src));
System.out.println(Arrays.toString(desc));
- 计算代码耗时
从1970年到现在的毫秒数
long time=System.currentTimeMillis();
//终止当前正在运行的虚拟机
System.exit(0)
//立即运行垃圾回收
System.gc();
- Math
在java.lang包中 java.lang包不需要导入
System.out.println(Math.PI);
//求两个数的最大值、最小值
int rs=Math.max(10,20)
int min=Math.min(5,6)
//返回一个[0,1)的随几数
Math.random();
//返回【0,100)之间的随机整数
(int)(Math.random()*100)
//开跟
double res=Math.sqrt(4);
6.大精度小数
BigDecimal num1=new BigDecimal("0.09");
BigDecimal num2=new BigDecimal("0.01);
System.err.println(num1.add(num2));
- 字符串
1、字符串分类:
可变字符串:定义号之后还可以再修改,改变不会创建新的内存地址
StringBuilder:没有synchronized 效率更高
StringBuffer:方法前面多加了synchronized 加锁更安全
不可变字符串String:定义好后j就不能再更改即内存地址不可变
String str="ABC";
str="aa";//会更改内存地址
String创建:
String str="ss";
String str2=new String("d");
String str3=null;//还没有初始化 没有分配内存空间
String str4="";//表示字符串,已经创建对象分配内存空间只是内容为空
2、字符串本质:
是一个char[]类型数组
private final char value[];
String、StringBuilder、StringBuffer都实现了CharSequence接口
3、字符串比较
==:比较两个内存地址是否相同
equals():先比较对象地址是否相等,如果不相等再比较内容是否相同
4、常量-》方法区当中有一个常量池
1)使用String str="add";创建字符串要么创建一个对象要么不创建对象
会先到常量池当中看一下有没有存在该字符串常量,如果已经有了就直接使用不会创建新的地址,如果没有就再当中创建一个新的对象
2)String str=new String("d");
至少得要创建一个对象,因为使用了new因此再堆中至少要创建一个对象
看一下常量池有没有对应的字符串常量,没有的话会再常量池创建一个字符串常量
5、字符串编译优化:
String str1="ABCD"
String str2="A"+"B"+"C"+"D";
String str3="AB"+"CD";
6、字符串常用方法:
1)把char[]转换成字符串
char[] cs=new char[]{'a','v'};
String str=new String(cs);
2)把字符串转成char[]
str.toCharArray();
3)获取字符串长度
str.length();
4)获取自负床当中某个字符
str.charAt(2);
5)返回一个子字符串再字符串中第一次出现的位置
String str="ABCDDCD"
String str1="CD";
str.indexOf(str1);
返回一个子字符串再字符串中最后一次出现的位置
str.lastIndexOf(str1);
6)大写字母转小写
str.toLowerCase();
7)小写字母转大写
str.toUpperCase();
8)忽略大小写比较
str1.equalsIgnoreCase(str);
7、字符串截取
String fileName="abc.java;adas;as";
String[] str=fileName.split(";");
for(String name:str){
//判断一个字符串是否以指定字符开头:
if(name.startWith("hello")){
int index=name.lastIndexOf(".");
String newName=name.substring(index);
}
}
String name="myxq";
String res=name.substring(0,1);
res=res.toUpperCase();
String laststr=name.substring(1);
str=res+laststr;
8、字符串去空格
1))去除首尾空格
String str=" my xq ";
s=str.trim();//去掉首尾的空格 不能去掉中间的空格
2)去掉所有空格
s=str.replace(" ","");
9、性能排名
String<StringBuffer<StringBuilder
10、StringBuilder使用
创建可变字符串 容量为16,如果超过的话会自动扩容。可变字符串本质还是char[]
StringBuilder sb=new StringBuilder();
等价于
StringBuilder sb=new StringBuilder(16);
链式编程
sb.append("ada");
删除指定位置字符
sb.deleteCharAt(1);
可变字符串转变称不可变字符串
String s=sb.toString();
字符串的反转
sb.reverse();
- Random
十三、集合
- Collection
1、集合:未来存放数据的容器
2、数组:
1)长度固定 不能再添加元素
3、java集合类:
1)长度可变
2)能存储任意对象
3)长度随着元素的增加二增加
4、数组和集合区别:
1)数组能存放基本数据类型 和引用数据类型
2)集合只能存放引用数据类型
5、什么时候使用数组和集合类
1)如果元素个数固定则使用数组,否则使用集合类
6、ArrayList
1)List已经覆盖了toString,直接可以打印内容结果
2)List可以添加重复元素 返回结果都是true
3)Set当中不能添加重复元素 天界则返回false
4)添加基本数据类型回自当装箱
Collection c=new ArrayList();
boolean b1=c.add("ad");
boolean b2=c.add(10);//自动装箱
boolean b3=c.add(true);//自动装箱
boolean b4=c.add("ab");//可以添加重复元素
c.remove("a");
c.clear();
System.out.println(c.isEmpty());
System.out.println(c.size());
Collection c1=new ArrayList();
Collection c2=new ArrayList();
c2.add("a");
c2.add("b");
c1.addAll(c2);
c1.removeAll(c2);
c1.containsAll(c2);//判断调用集合是否全部包含传入集合
boolean b=c1.retainsAll(c2);//取交集 把交集的结果赋值给调用者,如果调用的集合改变返回true否则返回false
集合元素的遍历(转换成数组方式):
Objict[] arr=c.toArray();
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
Collection c2=new ArrayList();
c2.add(new Dog("wc"));
c2.add(new Dog("wc2"));
Object[] arr2=c2.toArray();
for(int i=0;i<arr2.length;i++){
Dog d=(Dog)arr2[i];
System.out.println(d.getName());
}
集合元素遍历(迭代器方式):
Iterator it=c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
while(it.hasNext()){
Cat cat=(cat)it.next();
cat.show();
System.out.println(it.next());
}
- ArrayList底层结构
数组:数组被初始化之后就不会被改变
ArrayList:底层使用数组实现,查询修改比较快添加删除比较慢。把原有数据复制出来,再创建一个新数组容量增加50%,把复制的数组放到新数组当中原来的数组被扔掉。
去除集合当中重复元素:
ArrayList list=new ArrayList();
list.add(10);
//1、创建一个新集合
ArrayList newList=new ArrayList();
//2 依次取出每一个元素
ListIterator it=list.listIterator();
while(it.hasNext())
{
Object obj=it.next();
if(!newList.contains(obj)){
newList.add(obj);
}
}
- List
List:有角标
List list=new ArrayList();
list.add("Ad");
list.add("b");
list.add("c");
//根据角标添加
list.add(1,"mxh");
//获取指定角标数据
System.out.println(list.get(0));
//java.util.ConcurrentModificationException
//并发修改异常
//再迭代集合过程中不允许修改集合结构
//遍历元素 如果元素d等于把2删除
Iterator it=list.iterator();
while(it.hasNext()){
String str=(String)it.next();
if(str.equals(2)){
list.remove(2);
}
}
//删除正在迭代的元素 这样才正确
Iterator it=list.iterator();
while(it.hasNext()){
String str=(String)it.next();
if(str.equals(2)){
it.remove();
}
}
//解决添加元素的异常
ListIterator it=list.listIterator();
while(it.hasNext()){
String str=(String)it.next();
if(str.equals(2)){
it.add("2");
}
}
- LinkedList
1、底层使用链表
2、创建和添加元素
LinkedList list=new LinkedList();
list.add("a");
list.add("b");
list.add("c");
3、遍历
ListIterator it=list.listIterator();
while(it.hasNext())
{
System.out.println(it.next());
}
4、LinkedList 特有方法
list.addFirst("myxq");
list.addLast("gxq");
list.removeFirst();
list.removeLast();
Object obj=list.get(0);
5、栈操作
Stack s=new Stack();
s.push("a");
s.push("b");
s.push("c");
System.out.println(s);
6、栈实现
//LinkedList实现栈结构存储
class Stack{
LinkedList list;
Stack(){
list=new LinkedList();
}
//入栈
void push(Object obj)
{
list.addLast(obj);
}
//出栈
void pop()
{
list.removeLast();
}
@Override
public String toString()
{
return "Stack [linkedlist="+list+"]";
}
}
- Vector
1、创建
public static Vector createVector()
{
Vector vc=new Vector();
vc.add("a");
vc.add("b");
return vc;
}
2、遍历
public static void test(Vector vc)
{
//获取所有元素
Enumeration e=vc.elements();
while(e.hasMoreElements())
{
System.out.println(e.nextElement());
}
}
十四 泛型
1、泛型定义:
广泛通用的类型(一开始不确定是什么类型再使用时才确定类型)
2、定义分为两步:
1、再类的后面加<T> T表示不确定的类型 再创建对象s时才确定时什么类型
2、再变量前面加T
class Point<T>{
T x;
T y;
}
public class GenericsTest {
public static void main(String[] args) {
//没有指明T是什么类型时 默认是Object
Point p=new Point();
//T为String类型 注意T一定为引用类型
Point<String> p2=new Point<String>();
p2.x="a";
p2.y="z";
}
}
3、集合加泛型
1)集合中没有定义泛型,取出来的元素都是Object.定义泛型就不需要去强制转型
2)ArrayList<String> list=new ArrayList<String>();前后类型保持一致
从java7开始后面的类型可以不写。
3)泛型没有继承:ArrayList<Object> list=new ArrayList<String>();
4)泛型是一个语法糖(本质还是Object 内部其实还是要做强转)
public static void listGenerics()
{
ArrayList<String> list=new ArrayList<String>();
}
4、泛型类
1)再类上面定义的泛型,再创建对象时要指明泛型的类型(没指明默认为Object)
Test<String> t=new Test<String>();
2)泛型当中定义的泛型只能用在普通方法上,不能再静态方法中使用。
因为静态方法是直接用类名调用,泛型是再创建对象的时候才去指定类型。
class Test<T>{
public static T getName(){}//错误 只能使用再普通方法中,不能再静态方法中使用。
}
5、泛型方法
1)方法当中定义的泛型,再使用方法时参数传递确定具体是什么类型
方法想要单独使用泛型,必须得要有参数才有意义。
<T> void test(T a){
}
//静态方法也可以使用泛型
static <E> E test(E a){}
6、泛型通配符
通配符:不知道使用什么类型接受时,可以使用?表示未知。
//通配符的使用
List<String> list =new ArrayList<>();
wildcardCharacter(list);
public static void wildcardCharacter(List<?> list){}
通配符只能用来接收使用,不能做添加操作。
List<?> list=new ArrayList();
list.add("a");//报错 通配符只能用来接收使用
7、泛型上线和下限
//泛型上线 用来限定元素的类型必须得是指定类型的子类
public static void test01(List<? extends Number> list)
{
}
//泛型下线 用来限定元素的类型必须得是指定类型的父类
public static void test02(List<? super Number> list)
{
}
8、泛型擦除
List<String>list=new List<String>();
List list2=null;
list2=list;//把list中的泛型擦掉了
list2.add(2);
9、数组转集合
//数组转集合的相互转换
public static void listAndArray(){
int[] arr={10,20,30};
//把数组转成集合
//转换后,可以以面向对象的方式操作数组(除了不能添加和删除元素之外 集合当中的其它东西都可以使用)
List<int[]> list= Arrays.asList(arr);
list.add(10);//数组转集合并不能添加元素
//基本数据类型转成集合时,时再基本数据类型的数组当作一个对象
//再开发当中不会把基本数据类型的数组z转成集合
System.out.println(list.size());//结果为1
//引用数据类型的s数组才去转成集合
Integer[] arr2={10,20,30};
List<Integer> list2=Arrays.asList(arr2);
System.out.println(list2);
10、集合转数组
//集合转数组
public static void test2(){
List<String> list3=new ArrayList<>();
list3.add("a");
Object[] o=list3.toArray();
String[] strArr=list3.toArray(new String[0]);//静态开辟空间 如果开辟的空间小于size
//会自动创建一个和size一样大小的空间
System.out.println(Arrays.toString(strArr));
}
11、集合嵌套
//集合嵌套
public static void test3(){
Point p1=new Point();
Point p2=new Point();
List<Point> c1=new ArrayList<>();
c1.add(p1);
c1.add(p2);
Point p3=new Point();
Point p4=new Point();
List<Point> c2=new ArrayList<>();
c1.add(p3);
c1.add(p4);
List<List<Point>> x=new ArrayList<>();
x.add(c1);
x.add(c2);
for(List<Point> p:x)
{
for(Point g:p)
{
System.out.println(g.x);
}
}
}
12、set集合
//Set中存储的数据是无序的,不能添加重复元素
public static void test4()
{
HashSet<String> hs=new HashSet<>();
boolean res1=hs.add("a");
boolean res2=hs.add("a");//不能添加重复元素
hs.add("b");
hs.add("c");
Iterator it=hs.iterator();
while(it.hasNext())
{
String data= (String) it.next();
}
//能使用迭代器的都可以使用增强
for(String str:hs)
{
System.out.println(str);
}
}
//Set自定义类型去重
//1、在Person中要覆盖equals方法 2、覆盖hashCode 如果两个对象s属性完全相同 就判断是同一个对象
//右键 ->source ->选择equals hashCode
public static void test5()
{
HashSet<Person> hs=new HashSet<Person>();
//每一个对象都会有一个hasCode hashCode就是跟内存地址对应的一个编号,每一个对象的hashCode都不同
//当两个对象的 hashCode相同时不会调用equals 不相同时才会调用equals 如果equals然会为true就不添加
hs.add(new Person("zs",10));
hs.add(new Person("zs",10));
}
13、LinkeHashSet
//LinkedHashSet 时HashSet的子类
//底层使用链表实现,HashSet能保证元素的唯一
//能保证存在哪就在哪 不像HashSet无序
public static void test6()
{
LinkedHashSet<String> hs=new LinkedHashSet<>();
}
//去除重复字符串
public static void test7()
{
LinkedHashSet<Character> hs=new LinkedHashSet<>();
String str="aaaaabsbb";
char[] arr=str.toCharArray();
for(int i=0;i<arr.length;i++)
{
char c=arr[i];hs.add(c);
}
System.out.println(hs);
}
14、TreeSet
//TreeSet
//也是无序的 但会对集合元素进行排序 且可以保证元素唯一
//TreeSet当中存放的必须是同一类型
//自定义对象不能直接添加到TreeSet当中
//想要添加到TreeSet当中必须实现Comparable接口 覆盖当中一个方法compareTo
public static void test8()
{
TreeSet<Per> tr=new TreeSet<>();
tr.add(new Per("z",12));
}
class Per implements Comparable<Per>{
String name;
int age;
public Per(String name,int age)
{
this.name=name;
this.age=age;
}
//如果返回0:只添加一个元素
//如果返回正数:都能添加进去 顺序如何添加就如何显示
//如果返回负数:都能添加进去 顺序如何添加就如何倒序显示
@Override
public int compareTo(Per o) {
return 0;
}
//TreeSet二叉树原理分析
在添加元素时,会调用compareTo方法,如果该方法返回为0,认为添加的元素和集合当中的元素相等,如果返回值是-1比根元素小,就会放到左边,如果返回的是一个正数就会放到右边
//TreeSet自定义对象属性排序
@Override
public int compareTo(Per obj) {
int num=this.age-obj.age;
return num==0? this.name.compareTo(obj.name): num;
}
public static void test8()
{
TreeSet<Per> tr=new TreeSet<>();
tr.add(new Per("z",20));
tr.add(new Per("z",21));
}
//TreeSet比较器
//TreeSet比较器
public static void test9()
{
//默认情况下 比较时会调用对象的compareTo进行比较
//如果你传入比较器,就不会调用compareTo 就会使用你传入的比较器比较
TreeSet<String> tr=new TreeSet<>(new CompareLength());
tr.add("aaaa");
tr.add("z");
tr.add("asd");
System.out.println(tr);//按照长度进行排序
}
class CompareLength extends Object implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
int length=o1.length()-o2.length();
return length==0? o1.compareTo(o2):length;
}
}
}
15、Map映射
class Student{
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public static void test11()
{
/*
A集合 B集合
A集合当中的每一个元素都可以在B集合当中找到唯一一个值与之对应
A集合当中的元素不能重复(Set)
A集合当中每一个元素称为Key
B集合当中每一个元素是Value
*/
Map<String,Object> map=new HashMap<String,Object>();
//往A B两个集合当中添加元素并关联在一起
//map当中的元素不是有序的
//添加元素
Object res1=map.put("zs",20);
Object res2=map.put("ww",22);
Object res3=map.put("lx",19);
System.out.println(map);
//如果key值是第一次添加就返回null
System.out.println(res1);
System.out.println(res2);
//如果不是第一次添加 就用value把以前相同key对应的value替换
Object res4=map.put("zs",30);
//获取keys values
Set<String> set=map.keySet();//获取map中的所有keys
System.out.println(set);
Collection<Object> values=map.values();//获取map中的所有values
//删除
map.remove("zs");//根据map删除
map.clear();//删除所有
//长度功能
System.out.println(map.size());
//获取一个元素
Object value=map.get("zs");
//获取所有元素
Set<String> s=map.keySet();
Iterator<String> it=s.iterator();
while(it.hasNext())
{
String key=it.next();
Object val=map.get(key);
System.out.println(key+"="+val);
}
for(String key:map.keySet()) {
System.out.println(key + "=" + map.get(key));
}
//entry
Set<Map.Entry<String, Object>> entrySet=map.entrySet();
Iterator<Map.Entry<String, Object>> its=entrySet.iterator();
while(its.hasNext())
{
Map.Entry<String, Object> en=its.next();
String key= (String) ((Map.Entry) en).getKey();
Integer v= (Integer) (en).getValue();
System.out.println(key+"="+value);
}
//Map自定义对象作为key
HashMap<Student,String> hm=new HashMap<>();
hm.put(new Student("zs",20),"北京");
hm.put(new Student("zs",20),"深证");
hm.put(new Student("ls",20),"上海");
//LinkedHashMap 添加的元素是有顺序的 你怎么放的打印时就是怎样显示的
LinkedHashMap<String,Integer> hm2=new LinkedHashMap<>();
hm2.put("zs",20);
hm2.put("ww",20);
hm2.put("ls",20);
}