泛型
泛型的引入
我们写下面这样的代码,发现是有一些小问题的,因为我们同时存储了String类型和Integer类型的数据,但都给它转成了String类型,在运行的时候就会报错,相反,数组在存储数据的时候,只能存储一个类型的数据,这也算是数组的一个优点,那,在集合中有没有这样的做法,在创建的时候就明确了元素的数据类型,这样我们在插入数据或者是向下转型的时候,直接在编译时期报错,在集合中,这种设计我们叫做:泛型。
泛型的介绍
泛型:
一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的类型。参数化类型,把类型当作参数一样传递
格式:
<数据类型> 注意:此处的数据类型只能是引用类型
泛型的好处 把运行时期的问题提前到了编译时期 避免了强制类型转换 优化程序,消除黄色警告线 泛型的举例应用 泛型存储String类型数据举例
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String r = iterator.next();
System.out.println(r);
}
}
}
泛型存储自定义对象举例
class Student{
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name = name;
this.age = age;
}
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 class ArrayListDemo2 {
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
Student s1 = new Student("zhangsan", 21);
Student s2 = new Student("lisi", 22);
Student s3 = new Student("wangwu", 23);
list.add(s1);
list.add(s2);
list.add(s3);
Iterator<Student> iterator = list.iterator();
while (iterator.hasNext()){
Student next = iterator.next();
System.out.println(next.getName()+"---"+next.getAge());
}
}
}
泛型类
泛型类:把泛型定义在类上
这里仅仅表示的是一种参数类型,参数类型是一种变量,既然是变量,就满足我们变量的命名规则,可以是任何符合标识符的名字
public class GenericTool<T> {
private T obj;
public T getObj(){
return obj;
}
public void setObj(T obj){
this.obj = obj;
}
}
public static void main(String[] args) {
GenericTool genericTool = new GenericTool();
genericTool.setObj(new String("zhangsan"));
Object obj = genericTool.getObj();
String obj1 = (String) obj;
System.out.println(obj1);
genericTool.setObj(new String("lisi"));
Object obj2 = genericTool.getObj();
String obj21 = (String) obj2;
System.out.println(obj21);
GenericTool<String> stringGenericTool = new GenericTool<String>();
stringGenericTool.setObj("wangwu");
String obj3 = stringGenericTool.getObj();
System.out.println(obj3);
}
}
泛型方法
public class GenericTool2 {
public <T> void show(T t){
System.out.println(t);
}
}
public static void main(String[] args) {
GenericTool2 genericTool2 = new GenericTool2();
genericTool2.show("hello");
genericTool2.show("world");
genericTool2.show("java");
}
}
泛型接口
public interface GenericTool3<T>{
public abstract void show(T t);
}
public class GenericTool3Impl<T> implements GenericTool3<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
public static void main(String[] args) {
GenericTool3Impl<String> tool3 = new GenericTool3Impl<>();
tool3.show("hello");
GenericTool3Impl<Integer> tool31 = new GenericTool3Impl<>();
tool31.show(100);
}
}
泛型高级
public class GenericDemo2 {
public static void main(String[] args) {
ArrayList<Object> a1 = new ArrayList<Object>();
ArrayList<? extends Animal> o1 = new ArrayList<Animal>();
ArrayList<? extends Animal> o2 = new ArrayList<Dog>();
ArrayList<? extends Animal> o3 = new ArrayList<Cat>();
ArrayList<? super Animal> alist1 = new ArrayList<Object>();
ArrayList<? super Animal> alist4 = new ArrayList<Animal>();
}
}
public class Animal {
}
public class Cat extends Animal {
}
public class Dog extends Animal {
}
增强for循环
增强for循环
什么是增强for循环
JDK1.5之后出现了一些新内容:
- 自动装箱和拆箱
- 泛型
- 增强for循环
增强for循环:是for循环的一种,简化数组和Collection集合的遍历 for(元素数据类型 变量:数组或者Collection集合){ 使用变量即可,该变量就是元素 } 好处:简化了数组和Collection集合的遍历 增强for循环举例 注意:增强for可多次使用,迭代器只能使用一次,生命周期就结束了(因为迭代器只遍历一次,指针指到末尾就结束了)
public static void main(String[] args) {
int []arr = new int[]{1,2,3,4,5,6};
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
for(int i:arr){
System.out.println(i);
}
ArrayList<String> strings = new ArrayList<>();
strings.add("hello");
strings.add("world");
strings.add("java");
for(String s:strings){
System.out.println(s);
}
List<String> list1 = null;
if(!(list1 == null)){
for (String s1:list1) {
System.out.println(s1);
}
}
for(String s:strings){
if("java".equals(s)){
strings.add("spark");
}
}
}
存储自定义对象,加入泛型,并且使用增强for循环遍历
public static void main(String[] args) {
ArrayList<Student1> list = new ArrayList<Student1>();
Student1 s1 = new Student1("zhangsan", 21);
Student1 s2 = new Student1("lisi", 22);
Student1 s3 = new Student1("wangwu", 23);
list.add(s1);
list.add(s2);
list.add(s3);
for(Student1 s:list){
System.out.println(s.getName()+"---"+s.getAge());
}
静态导入与可变参数
静态导入 什么是静态导入 import static 包名…类名.方法名;(可以直接导入到方法的级别)
注意 方法必须是静态 如果本类中有其他与静态导入的方法重名的,优先使用本类的方法 如果导入的时候有的方法重名了,怎么办,最好加前缀,规定必须加,这个意义不大,看懂即可
public static void main(String[] args) {
System.out.println(Math.abs(-100));
System.out.println(Math.pow(2,3));
System.out.println(Math.max(100,200));
System.out.println(abs(-900));
FunDemo.show("hello");
com.bigdata.shujia19.FunDemo.show(12.34);
}
}
可变参数 什么是可变参数,以及可变参数的注意点 可变参数:定义方法的时候,方法的参数可以有多个 修饰符 返回值类型 方法名(数据类型…变量名){} 注意:这里变量,其实就是把多个参数,组成一个数组,给它起个名字,这个变量就是数组名 可变参数代码举例:
public static void main(String[] args) {
int a = 10;
int b = 20;
int result1 = sum(a,b);
System.out.println(result1);
int c = 30;
int result2 = sum1(a,b,c);
System.out.println(result2);
int res4 = sum(a,b,c,40,50,20,304,70);
System.out.println(res4);
}
public static int sum(int a,int b){
return a+b;
}
public static int sum1(int a,int b,int c){
return a+b+c;
}
public static int sum(int...arr){
int sum = 0;
for(int i:arr){
sum += i;
}
return sum;
}
}
Set集合
Set接口 Set接口的引入 Collection接口下有List和Set接口
List 元素有序(存储顺序和取出顺序一致,可以重复) Set 无序(存储顺序和取出顺序不一致,元素唯一) HashSet:底层是hash表,线程不安全,效率高,有时候,给的顺序正好好存储的顺序一致,但这并不代表有序,可以多试试看,元素唯一,无序
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("hello");
hashSet.add("world");
hashSet.add("java");
hashSet.add("hello");
hashSet.add("world");
for(String s:hashSet){
System.out.println(s);
}
}
}
HashSet类 HashSet类概述 不保证set的迭代顺序 特别是不保证该顺序恒久不变 public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<String>();
hashSet.add("hello");
hashSet.add("world");
hashSet.add("java");
hashSet.add("hello");
hashSet.add("world");
for(String s:hashSet){
System.out.println(s);
}
}
HashSet如何保证元素的唯一性 底层数据结构是哈希表(元素是链表的数组) 哈希表依赖于哈希值存储 添加功能底层依赖的两个方法 int hashCode() boolean equals(Object obj) public static void main(String[] args) { /* 定义一个HashSet集合存储自定义对象,并保证元素的唯一性 要求:如果两个对象的成员变量的值相同,说明是同一个元素
按照需求我们写完了程序,但是并没有去重,所以这不是符合我们要求的
又因为,我们知道了HashSet底层是依赖HashCode()和equals()方法的
又因为学生类中没有重写,比较的是Object中的方法,默认比较的是地址值,
每个学生都是new出来的,所以地址值都不一样,所以就都插进去了
我们现在要去重写HashCode()和equals()方法,不需要我们自己手动写,自动生成即可
*/
HashSet<Student> list = new HashSet<Student>();
Student s1 = new Student("zhangsan", 21);
Student s2 = new Student("lisi", 22);
Student s3 = new Student("wangwu", 23);
list.add(s1);
list.add(s2);
list.add(s3);
for(Student s:list){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
HashSet中add方法的源码
public interface Collection<E> extends Iterable<E>{
...
}
public interface Set<E> extends Collection<E>{
...
}
public class HashSet<E> implements Set<E>{
private transient HashMap<E,Object> map;
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
}
HashSet中add自定义对象存储图解
LinkedHashSet LinkedHashSet:底层由哈希表和链表组成 哈希表保证元素的唯一性 链表保证元素的顺序,有序,(存储和取出的顺序一致)
public static void main(String[] args) {
LinkedHashSet<String> strings = new LinkedHashSet<String>();
strings.add("hello");
strings.add("world");
strings.add("java");
for(String s:strings){
System.out.println(s);
}
}
}
感谢阅读,我是啊帅和和,一位大数据专业即将大四学生,祝你快乐。
|