【1】数组,集合都是对多个数据进行存储 *** 作的,简称为容器。
PS:这里的存储指的是内存层面的存储,而不是持久化存储(.txt,.avi,.jpg,数据库)。
特点:
(1)数组一旦指定了长度,那么长度就被确定了,不可以更改。
int[] arr = new int[6];
(2)数组一旦声明了类型以后,数组中只能存放这个类型的数据。数组中只能存放同一种类型的数据。
int[] arr,String[] s,double[] d.....
缺点:
(1)数组一旦指定了长度,那么长度就被确定了,不可以更改。
(2)删除,增加元素 效率低。
(3)数组中实际元素的数量是没有办法获取的,没有提供对应的方法或者属性来获取
(4)数组存储:有序,可重复 ,对于无序的,不可重复的数组不能满足要求。
【2】正因为上面的缺点,引入了一个新的存储数据的结构---》集合
增加:add(E e) addAll(Collection extends E> c)
删除:clear() remove(Object o)
修改:
查看:iterator() size()
判断:contains(Object o) equals(Object o) isEmpty()
public static void main(String[] args) {
Collection col = new ArrayList();
//添加
//1、add(E e)
col.add(18);
System.out.println(col/*.toString()*/);
//2、addAll(Collection extends E> c)
List list = Arrays.asList(new Integer[]{11, 15, 3, 7, 1});
col.addAll(list);
//删除、
//1、clear()
//col.clear();清空集合
System.out.println(col);
System.out.println("集合中元素的数量为:"+col.size());
System.out.println("集合是否为空:"+col.isEmpty());
//2、remove(Object o)
boolean isRemove = col.remove(15);
System.out.println(col);
System.out.println("集合中数据是否被删除:"+isRemove);
//判断
Collection col2 = new ArrayList();
col2.add(18);
col2.add(12);
col2.add(11);
col2.add(17);
Collection col3 = new ArrayList();
col3.add(18);
col3.add(12);
col3.add(11);
col3.add(17);
System.out.println(col2.equals(col3));
System.out.println(col2==col3);//地址一定不相等 false
System.out.println("是否包含元素:"+col3.contains(117));
}
2、注意:
接口不能创建对象,利用实现类创建对象
Collection col = new ArrayList();
只能存放引用数据类型的数据,不能是基本数据类型
基本数据类型自动装箱,对应包装类。int--->Integer
Collection集合遍历方式:方式一:
public static void main(String[] args) {
Collection col = new ArrayList();
col.add(18);
col.add(12);
col.add(11);
col.add(17);
col.add("abc");
col.add(9.8);
//方式1:增强for循环
for(Object o:col){
System.out.println(o);
}
}
方式二:
public static void main(String[] args) {
Collection col = new ArrayList();
col.add(18);
col.add(12);
col.add(11);
col.add(17);
col.add("abc");
col.add(9.8);
//方式2:iterator()迭代器
Iterator it = col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
注意:不能用普通for循环遍历,因为没有可以调用的方法
/*for(int i= 0;i
(一)List系列集合
1、常用方法
增加:add(int index, E element)
删除:remove(int index) remove(Object o)
修改:set(int index, E element)
查看:get(int index)
添加:
List list = new ArrayList();
list.add(13);
list.add(17);
list.add(6);
list.add(-1);
list.add(2);
list.add("abc");
System.out.println(list);
//在某个索引处添加
list.add(3,66);
System.out.println(list);
list.set(3,77);
System.out.println(list);
删除:
list.remove(2);
//在集合中存入的是Integer类型数据的时候,调用remove方法调用的是:remove(int index)
//根据索引来删除
System.out.println(list);
list.remove("abc");
System.out.println(list);
修改:
list.set(4,55);
System.out.println(list);
list.set(4,99);
System.out.println(list);
查看:
Object o = list.get(0);
System.out.println(o);
2、List遍历集合方式
方式一:
//方式1:普通for循环:
System.out.println("---------------------");
for(int i = 0;i
方式二:
//方式2:增强for循环:
System.out.println("---------------------");
for(Object obj:list){
System.out.println(obj);
}
方式三:
//方式3:迭代器:
System.out.println("---------------------");
Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
ArrayList:
包含一定泛型类容,以及对集合的一些补充
CSDNhttps://mp.csdn.net/mp_blog/creation/editor/124676600
泛型:方便以后API的阅读
1、概述:泛型就相当于标签
形式:<>
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,
JDK1.5之 后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。
泛型类的定义和实例化:
//GenericTes就是一个普通的类
//GenericTest 就是一个泛型类
//<>里面就是一个参数类型,这个类型现在是不确定的,相当于一个占位
public class GenericTest {
int age;
String name;
E sex;
public void a(E n){
}
public void b(E[] m){
}
}
class Test{
//这是main方法,程序的入口
public static void main(String[] args) {
//GenericTest进行实例化:
//(1)实例化的时候不指定泛型:如果实例化的时候不明确的指定类的泛型,那么认为此泛型为Object类型
GenericTest gt1 = new GenericTest();
gt1.a("abc");
gt1.a(17);
gt1.a(9.8);
gt1.b(new String[]{"a","b","c"});
//(2)实例化的时候指定泛型:---》推荐方式
GenericTest gt2 = new GenericTest<>();
gt2.sex = "男";
gt2.a("abc");
gt2.b(new String[]{"a","b","c"});
}
}
继承情况:
(1)父类指定泛型
class SubGenericTest extends GenericTest{
}
class Demo{
//这是main方法,程序的入口
public static void main(String[] args) {
//指定父类泛型,那么子类就不需要再指定泛型了,可以直接使用
SubGenericTest sgt = new SubGenericTest();
sgt.a(19);
}
}
(2)父类不指定泛型
如果父类不指定泛型,那么子类也会变成一个泛型类,那这个E的类型可以在创建子类对象的时候确定
class SubGenericTest2 extends GenericTest{
}
class Demo2{
//这是main方法,程序的入口
public static void main(String[] args) {
SubGenericTest2 s = new SubGenericTest2<>();
s.a("abc");
s.sex = "女";
}
}
细节:
(1)泛型类可以使用多个参数类型:
public class TestGeneric{
A age;
B name;
C sex;
public void a(A m,B n,C x){
}
}
(2) 泛型类的构造器的写法:
public TestGeneric(){
}
(3)不同泛型的引用类型不可以相互赋值
public void(){
ArrayList list1 = null;
ArrayList list2 = null;
//list1 = list2;报错
}
(4)当泛型参数存在继承情况时
Object obj = new Object();
String s = new String();
obj = s;//多态的一种形式
Object[] objArray = new Object[10];
String[] strArray = new Stirng[10];
objArray = strArray;//多态的一种形式
List
总结:当A和B是子类父类的关系的时候,G和G不存在继承的关系,它们是并列的关系
(5)泛型如果不指定,对应类型就会变为Object类型,即可以添加任何引用类型的数据
(6)泛型类中的静态方法不能调用类的泛型:
public class TestGeneric{
A age;
B name;
C sex;
public static int c(A a){
//报错
return 10;
}
}
原因:static方法在对象之前创建,而泛型类型还未确定
(7)不可以直接使用E[]的创建
public void a(A a,B b,C c){
//不可以:A[] i = new A[10];
A[] i = (A[])new Object[]10;
}
泛型方法:
泛型方法对应的那个泛型参数类型,和当前所在的这个类,是否是泛型类,泛型是什么无关
public class TestGeneric {
//不是泛型方法 (不能是静态方法)
public static void a(E e){
}
//是泛型方法
public static void b(T t){
}
}
class Demo{
//这是main方法,程序的入口
public static void main(String[] args) {
TestGeneric tg = new TestGeneric<>();
tg.a("abc");
tg.b("abc");
tg.b(19);
tg.b(true);
}
注:
①泛型方法定义的时候,前面要加上
②泛型方法可以是静态方法
③ 泛型方法的泛型在调用方法时传入
通配符:
(1)概述:A 和 B是子类父类的关系,G和G不存在子类父类关系,是并列的
加入通配符?后,G>就变成了 G和G的父类
List
(2)通配符使用细节:
public void a(List> list){
//1.遍历:
for(Object a:list){
System.out.println(a);
}
//2.数据的写入 *** 作 :
//list.add("abc");-->出错,不能随意的添加数据,因为泛型类型不确定
list.add(null);
//3.数据的读取 *** 作:
Object s = list.get(0);
}
泛型受限:
定义一个Student类和Person类,Student类继承Person类
定义三个并列关系的集合
List
(1)使用泛型受限:泛型的上限
List extends Person> list1 = null;
//list1 = a;报错
list1 = b;
list1 = c;
解释:List extends Person>就相当于List extends Person>是List
(2)使用泛型受限:泛型的下限
List super Person> list2 = null;
list2 = a;
list2 = b;
//list3 = c;报错
解释: List super Person>就相当于List super Person>是List
增加 addFirst(E e) addLast(E e)
offer(E e) offerFirst(E e) offerLast(E e)
删除 poll()
pollFirst() pollLast() ---》JDK1.6以后新出的方法,提高了代码的健壮性
removeFirst() removeLast()
查看 element()getFirst() getLast()
indexOf(Object o) lastIndexOf(Object o)
peek()
peekFirst() peekLast()
LinkedList list = new LinkedList<>();
list.add("aaaaa");
list.add("bbbbb");
list.add("ccccc");
list.add("ddddd");
list.add("eeeee");
list.add("bbbbb");
list.add("fffff");
list.addFirst("jj");//添加元素在头
list.addLast("hh");//添加元素在尾端
list.offer("kk");//添加元素在尾端
list.offerFirst("pp");//添加元素在头
list.offerLast("rr");//添加元素在尾端
System.out.println(list);//LinkedList可以添加重复数据
System.out.println(list.poll());//删除头上的元素并且将元素输出
System.out.println(list.pollFirst());
System.out.println(list.pollLast());
System.out.println(list.removeFirst());
System.out.println(list.removeLast());
System.out.println(list);//LinkedList可以添加重复数据
/*list.clear();//清空集合
System.out.println(list);*/
/*System.out.println(list.pollFirst());*/
/*System.out.println(list.removeFirst());报错:Exception in thread "main" java.util.NoSuchElementException*/
2、LinkedList遍历集合方式
(1)普通for循环
for(int i = 0;i
(2)增强for循环
for(String s:list){
System.out.println(s);
}
(3)迭代器
/*Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}*/
//下面这种方式好,节省内存
for(Iterator it = list.iterator();it.hasNext();){
System.out.println(it.next());
}
3、LinkedList简要底层原理图
(二)Set系列集合
Set集合的功能基本上与Collection的一致
特点:①无序:存取顺序不一致
②不重复:可以去除重复
③无索引:没有带索引的方法,所以不能使用for循环遍历,也不能通过索引来获取元素
HashSet: 特点:无序、不重复、无索引
Set sets = new HashSet<>();
sets.add("Java");
sets.add("Java");
sets.add("MySQL");
sets.add("MySQL");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
[MySQL, Java, HTML, SpringBoot]
//无序
底层原理:
①JDLK8之前的,底层使用数组+链表组成
●创建一个默认长度16的数组,数组名table
●根据元素的哈希值跟数组长度求余计算出应存入的位置(哈希算法)
●判断当前位置是否为null,如果是null直接存入
●如果位置不为空,则调用equals方法比较
●如果一样,则不存,如果不一样,则存入数组
◑新元素占老元素位置,指向老元素
②JDK8开始后,底层采用数组+链表+红黑树组成
◑新元素挂在老元素下面
当挂在元素下面的数据过多时,查询性能降低,于是,当链表长度超过8的时候,自动转换成红黑树
哈希值:是JDK根据对象的地址,按照某种规则算出来的int类型的数值
Object类的API:public int hashCode():返回对象的哈希值
对象哈希值的特点:
①同一个对象多次调用hashCode()方法返回的哈希值是相同的
②默认情况下,不同对象的哈希值是不同的
String name = "aaaa";
System.out.println(name.hashCode());
System.out.println(name.hashCode());
String name1 = "bbbb";
System.out.println(name1.hashCode());
System.out.println(name1.hashCode());
2986048
2986048
3016832
3016832
注意:
如果往HashSet中放入数据,需要重写hashCode和equals
学生类:
public class Student {
private String name;
private int age;
private char sex;
public Student() {
}
public Student(String name, int age, char sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
不重写的话:
public static void main(String[] args) {
Set sets = new HashSet<>();
Student s1 = new Student("无恙",20,'男');
Student s2 = new Student("无恙",20,'男');
Student s3 = new Student("周维",21,'男');
sets.add(s1);
sets.add(s2);
sets.add(s3);
System.out.println(sets);
}
[Student{name='周维', age=21, sex=男}, Student{name='无恙', age=20, sex=男}, Student{name='无恙', age=20, sex=男}]
//添加了两个信息一样的学生
重写:在学生类里右键,生成
一路next,即可生成
@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 && sex == student.sex && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
重写后:
[Student{name='无恙', age=20, sex=男}, Student{name='周维', age=21, sex=男}]
结论:
哈希表是一种对于增删改查数据性能都较好的结构
LinkedHashSet:特点:有序、不重复、无索引
Set sets = new LinkedHashSet<>();
sets.add("Java");
sets.add("Java");
sets.add("MySQL");
sets.add("MySQL");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
[Java, MySQL, HTML, SpringBoot]
//有序
原理:底层数据结构依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序
TreeSet: 特点:①可排序、不重复、无索引(按元素大小默认升序)
②TreeSet集合是基于红黑树的数据结构排序的,增删改查性能都较好
③TreeSet集合是一定要排序的,可将元素按照指定的规则进行排序
默认排序规则:●对于数值型,Integer,Double,官方默认按照大小进行升序排序
●对于字符串类型,默认按照首字符的编号升序排序
●对于自定义的Student对象,TreeSet无法直接排序(需制定排序规则)
数值型:
public static void main(String[] args) {
Set sets = new TreeSet<>();
sets.add(23);
sets.add(12);
sets.add(13);
sets.add(32);
sets.add(21);
sets.add(14);
System.out.println(sets);
}
[12, 13, 14, 21, 23, 32]
字符型:
Set sets1 = new TreeSet<>();
sets1.add("Java");
sets1.add("Java");
sets1.add("About");
sets1.add("Python");
sets1.add("UI");
sets1.add("UI");
System.out.println(sets1);
[About, Java, Python, UI]
自定义:
定义一个苹果类:
public class Apple {
private String name;
private String color;
private double price;
private int weight;
public Apple() {
}
public Apple(String name, String color, double price, int weight) {
this.name = name;
this.color = color;
this.price = price;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
", weight=" + weight +
'}';
}
}
Set apples = new TreeSet<>();
apples.add(new Apple("红富士","红色",9.9,500));
apples.add(new Apple("青苹果","绿色",15.9,300));
apples.add(new Apple("绿苹果","青色",29.9,400));
apples.add(new Apple("黄苹果","黄色",9.8,500));
System.out.println(apples);
因为无法对Apple排序,所以
所以,自定义排序规则
方法一:让自定义的类实现Comparable接口重写的comparaTo方法来制定比较规则
方式二:TreeSet集合有参数构造器,可以设置Comparator接口对应的比较对象,来制定比较规则
后续继续补充
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)