集合
Collection:- List: 元素有序且允许发生重复,有索引- ArrayList: 底层数据结构是数组,查询快,增删慢- Vector- LinkedList- Set:
例子:
public class ArrayListDemo1 {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add("hello");list1.add("world");list1.add("hello");list1.add("java");list1.add("flink");Iterator iterator = list1.iterator();while (iterator.hasNext()){Object o = iterator.next();System.out.println(o);}}
}
链表:
Collection:- List: 元素有序且允许发生重复,有索引- ArrayList: 底层数据结构是数组,查询快,增删慢,线程不安全的,效率高- Vector: 底层数据结构是数组,查询快,增删慢,线程安全的,效率低,即便是这样,我们以后也不用- LinkedList: 底层数据结构是双链表,增删快,查询慢,线程不安全,效率高- Set:
LinkedList:特有的功能
LinkedList类特有功能【由于底层是链表】public void addFirst(Object e)及addLast(Object e)public Object getFirst()及getLast()public Object removeFirst()及public Object removeLast()
例子:
public class LinkedListDemo1 {public static void main(String[] args) {//LinkedList() 构造一个空列表。LinkedList list1 = new LinkedList();list1.add("hello");list1.add("world");list1.add("hello");list1.add("clickhouse");list1.add("redis");System.out.println("list1: "+list1);// Iterator iterator = list1.iterator();
// while (iterator.hasNext()){
// System.out.println(iterator.next());
// }System.out.println("-----------------------------------------");//public void addFirst(Object e)及addLast(Object e) 在头部添加一个元素或者尾部添加元素list1.addFirst("kafka");list1.addLast("cdh");System.out.println("list1: "+list1);//public Object getFirst()及getLast()System.out.println(list1.getFirst());System.out.println(list1.getLast());System.out.println("list1: "+list1);//public Object removeFirst()及public Object removeLast() 从集合中移除第一个元素或最后一个元素System.out.println(list1.removeFirst());System.out.println(list1.removeLast());System.out.println("list1: "+list1);}
}
练习:
去除集合中字符串的重复值(字符串的内容相同)
去除集合中字符串的重复值(字符串的内容相同)
public class ArrayListTest1 {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add("hello");list1.add("world");list1.add("hello");list1.add("java");list1.add("flink");list1.add("hello");list1.add("java");list1.add("world");list1.add("hello");System.out.println("list1: "+list1);System.out.println("----------------------------");//创建一个新的集合,遍历旧集合//如果新集合中有该元素,说明重复,不添加//反之添加到新集合中,最后新集合中存储去重后的结果ArrayList list2 = new ArrayList();Iterator iterator = list1.iterator();while (iterator.hasNext()){String s = (String) iterator.next();if(!list2.contains(s)){list2.add(s);}}System.out.println("list2: "+list2);}
}
去除集合中自定义对象的重复值(对象的成员变量值都相同)
去除集合中自定义对象的重复值(对象的成员变量值都相同)
public class ArrayListTest2 {public static void main(String[] args) {ArrayList list1 = new ArrayList();Student s1 = new Student("张成阳", 18);Student s2 = new Student("方直", 19);Student s3 = new Student("张成阳", 18);Student s4 = new Student("方直", 19);Student s5 = new Student("张成阳", 18);Student s6 = new Student("方直", 19);list1.add(s1);list1.add(s2);list1.add(s3);list1.add(s4);list1.add(s5);list1.add(s6);System.out.println("list1: "+list1);System.out.println("----------------------------");//创建一个新的集合,遍历旧集合//如果新集合中有该元素,说明重复,不添加//反之添加到新集合中,最后新集合中存储去重后的结果ArrayList list2 = new ArrayList();Iterator iterator = list1.iterator();while (iterator.hasNext()){Student s = (Student) iterator.next();if(!list2.contains(s)){list2.add(s);}}/*我们按照去重字符串的逻辑对学生对象进行去重,发现不太行旧集合中的每一个学生对象都添加到了新集合中‘从结果来看。每一个学生对象41行的判断【!list2.contains(s)】都是truelist2.contains(s) 一直都是false要想知道为什么list2.contains(s)一直都是false的话,就应该去看contains的源码public boolean contains(Object o) {// o - new Student("张成阳", 18);return indexOf(o) >= 0;}public int indexOf(Object o) {// o - new Student("张成阳", 18);if (o == null) {for (int i = 0; i < size; i++)if (elementData[i]==null)return i;} else {for (int i = 0; i < this.size; i++) // 遍历新集合,调用元素的equals方法挨个与新集合中的元素进行比较if (o.equals(elementData[i]))return i; // i的值一定是大于等于0}return -1;}从源码上来看,底层是调用了元素类型中的equals方法,而我们的元素是学生类,学生类中没有重写该方法,用的是父类Object类中的equals方法,比较的是地址值,而每一学生都是new出来的,地址肯定不一样。解决方案:元素类型中重写equals方法即可*/System.out.println("list2: "+list2);}
}
请用LinkedList模拟栈数据结构的集合,并测试。栈的特点:先进后出
请用LinkedList模拟栈数据结构的集合,并测试栈的特点:先进后出题目的意思是:自己造一个类,底层封装LinkedList,自己定义方法创建自己的类对象,调用自己定义的方法,来实现栈。
解:
import java.util.LinkedList;public class MyStack {private LinkedList list;public MyStack(){list = new LinkedList();}public void shuJiaAddElement(Object o){list.addFirst(o);}public Object shuJiaGetElement(){return list.removeFirst();}public int getSize(){return list.size();}@Overridepublic String toString() {return "MyStack{" +"list=" + list +'}';}
}public class LinkedListTest1 {public static void main(String[] args) {MyStack myStack = new MyStack();myStack.shuJiaAddElement("hello");myStack.shuJiaAddElement("world");myStack.shuJiaAddElement("java");myStack.shuJiaAddElement("hello");myStack.shuJiaAddElement("hadoop");System.out.println("myStack: " + myStack);int size = myStack.getSize();for (int i = 0; i < size; i++) {System.out.println(myStack.shuJiaGetElement());}}
}
泛型
回忆下,在此之前,我们的集合可以存放任意类型的元素,但是实际开发的时候,一个集合规定只允许放一种数据类型的元素
java中的集合提供了一种类似于数组定义时确定元素类型的方式,泛型
泛型:语句定义格式:<引用数据类型>将引用数据类型当作参数一样传递
泛型的好处:
泛型的好处:1、减少了程序中的黄色警告2、遍历的时候不需要再做向下转型了,因为在创建集合对象的时候,给定了泛型的类型
public class FanXingDemo1 {public static void main(String[] args) {ArrayList<String> list1 = new ArrayList<>(); // 泛型定义了集合中的元素数据类型,右边的尖括号泛型可以不写,自动类型推断
// ArrayList list1 = new ArrayList();
// list1.add()
// list1.add(10);list1.add("hello");list1.add("world");list1.add("java");list1.add("hadoop");list1.add("world");list1.add("hello");list1.add("flink");
// list1.add(false);System.out.println("list1: "+list1);System.out.println("----------------------------");Iterator<String> iterator = list1.iterator();while (iterator.hasNext()){String s = iterator.next();System.out.println(s+"-"+s.length());}}
}
泛型将来遇到的场景
泛型类:将泛型定义在类上<>里面的参数是为了将来调用时接收传入的引用数据类型,相当于一个形参一样,符合变量标识符命名规则就可以了但是规范来说,泛型的名字,由一个大写的英文字母表示
class Demo1<A>{public void fun1(A a){System.out.println(a);}
}public class FanXingDemo2 {public static void main(String[] args) {Demo1<Integer> stringDemo1 = new Demo1<>();stringDemo1.fun1(100);
// stringDemo1.fun1("hello");Demo1<String> d2 = new Demo1<>();d2.fun1("hello");
// d2.fun1(100);}
}
把泛型定义在方法上 格式:public <泛型类型> 返回类型 方法名(泛型类型 .)
class Demo2<Q>{public <E> void fun1(E e){System.out.println(e);}public void fun2(Q q){System.out.println(q);}
}
public class FanXingDemo3 {public static void main(String[] args) {Demo2<Double> demo2 = new Demo2<>();demo2.fun1("hello");demo2.fun1(100);demo2.fun2(12.34);}
}
泛型接口
把泛型定义在接口上,格式:public interface 接口名<泛型类型1…>
interface Inter<W>{void fun1(W w);
}class InterImpl<W> implements Inter<W>{@Overridepublic void fun1(W w) {System.out.println(w);}
}public class FanXingDemo4 {public static void main(String[] args) {}
}
泛型通配符<?>
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E向下限定,E及其子类
? super E向上限定,E及其父类
class Animal {}class Dog extends Animal {}class Cat extends Animal {}class Demo3 {public void fun1(Collection<?> c1) { // 可以接收元素是任意引用数据类型的Collection集合对象System.out.println("c1: " + c1);}public void fun2(Collection<? extends Animal> c1) { // 可以接收元素是Animal类型或Animal的子类类型的的Collection集合对象System.out.println("c1: " + c1);}public void fun3(Collection<? super Animal> c1) { // 可以接收元素是Animal类型或Animal的父类类型的的Collection集合对象System.out.println("c1: " + c1);}// public void fun1(Xxxx<?> c1) { // 可以接收元素是任意引用数据类型的Xxxx对象
// System.out.println("c1: " + c1);
// }
}public class FanXingDemo5 {public static void main(String[] args) {Demo3 d1 = new Demo3();ArrayList<Animal> list1 = new ArrayList<>();ArrayList<Dog> list2 = new ArrayList<>();ArrayList<Cat> list3 = new ArrayList<>();ArrayList<Object> list4 = new ArrayList<>();//Collection<?> c1d1.fun1(list1);d1.fun1(list2);d1.fun1(list3);d1.fun1(list4);d1.fun2(list1);d1.fun2(list2);d1.fun2(list3);
// d1.fun2(list4);d1.fun3(list1);
// d1.fun3(list2);
// d1.fun3(list3);d1.fun3(list4);//public boolean addAll(Collection<? extends Animal> c)ArrayList<Animal> animals = new ArrayList<>();animals.addAll(list1);animals.addAll(list2);animals.addAll(list3);
// animals.addAll(list4);}
}
一些小知识点
增强for循环:是用来代替迭代器的,可以遍历数组和Collection集合语句定义格式:for(元素的数据类型 变量名 : 数组或Collection集合){使用变量名;}
例子
public class ZengForDemo {public static void main(String[] args) {ArrayList<String> list1 = new ArrayList<>();list1.add("hello");list1.add("world");list1.add("java");list1.add("hadoop");list1.add("world");list1.add("hello");list1.add("flink");System.out.println("list1: "+list1);System.out.println("----------------------------");for (String s : list1) {System.out.println(s + "-" + s.length());}
//
// for (String s : list1) {
// System.out.println(s + "-" + s.length());
// }System.out.println("----------------------------");int[] arr = {11,22,33,44,55};for(int i : arr){System.out.println(i);}}
}
导入方法例:max
package shujia.day10;
//import static java.lang.Math.max;
//import static java.lang.Math.min;import static java.lang.Math.*;public class StaticImportDemo {public static void main(String[] args) {
// System.out.println(Math.max(12,34));
// System.out.println(Math.max(23,1));
// System.out.println(Math.max(42,51));
// System.out.println(Math.max(12,124));System.out.println(max(123, 5));
// System.out.println(min(213, 6));System.out.println(Math.max(123,5));}public static int max(int a, int b) {return a + b;}
}
可变参数:
语句定义格式:数据类型... arr
注意事项
注意事项:1、方法定义时,如果有可变参数,可变参数必须在最后一个定义2、一个方法定义时,只能有一种类型是可变参数
例子:
public class KeBianCanDemo1 {public static void main(String[] args) {
// //需求:求两个int数之和
// int a = 3;
// int b = 4;
// sum(a, b);
//
// //需求:求三个int数之和
// int c = 5;
// sum(a, b, c);
// //需求:求n个int数之和
// int d = 6;
// sum(a,b,c,d);//调用方法,传入一个学生的姓名和若干门成绩stuScore("zcy",89,98);stuScore("fz",99,78,91);//可变参数使用的例子List<String> list = Arrays.asList("hello", "world", "hello", "java", "hadoop");}public static void stuScore(String name, int... scores){int sum = 0;for (int i : scores) {sum+=i;}System.out.println("姓名:"+name+"总成绩:"+sum);}public static void sum(int... arr) { // 可以传入若干个int类型的值,被封装到了一个数组中,数组的名字叫做arr
// System.out.println(a + b);int sum = 0;for (int i : arr) {sum+=i;}System.out.println(sum);}// public static void sum(int a, int b, int c) {
// System.out.println(a + b + c);
// }
//
// public static void sum(int a, int b) {
// System.out.println(a + b);
// }
}