第四周(异常到Collection集合)

day01

1.异常

1.1错误和异常

Java中的错误 Error: 是代表JVM本身的错误, 咱们程序员无法通过代码进行处理的

Error很少出现,一旦出现 就意味着大换血了

Java中的异常 Exception: 代表Java程序在运行过程中出现了不可预期的错,然后影响了代码的正常的执行,可以使用Java中的异常的处理机制来出来一下代码,让代码能够正常的执行下去。

1.2异常

Java中封装好了处理异常的机制。

Java异常分为两大类:

编译时异常: 在写代码的编译器会报红

FileNotFoundException

SQLException

ClassNotFoundExcetion

InterruptException

运行时异常: 在运行的时候 出现的异常

ArrayIndexOutOfBoundsException 数组下标越界的异常

当Java代码出现了异常,然后就可以是使用Java的处理机制来处理,如果没有出现异常就正常执行即可

1.3异常的捕捉

在程序运行的过程中,难免会出现异常,这个时候Java中捕捉异常的语法格式将会发现异常并进行异常的处理

try {
    可能出现异常的代码
} catch(异常对象) {
    语句体(一般是针对上方异常的处理方案)
}
//执行流程:如果try里面的代码没有出现异常,跳过catch,继续向下运行。
如果try里面代码有异常,就会执行catch大括号里面的语句体
public class Demo1 {
    public static void main(String[] args) {
        int[] arr = {5, 3, 9, 10, 8};
        try {
            int a = arr[9];//可能出现异常的代码
        } catch (Exception e) {//代码出现异常的原因
            System.out.println("下标越位");//出现异常的解决办法
        }
​
    }
}
​

1.4异常的抛出

在代码出现异常的地方进行抛出异常,特别是关于编译时异常的时候,为了保证代码能够编译通过,可以使用抛出异常的方式进行抛出异常

throws:关键字 名词 告知使用者 此处有异常 一定要注意一下别写错了

public class Demo1 {
    public static void main(String[] args) throws Exception  {//进行了异常的抛出
​
        Thread.sleep(1000);//编译时出现了异常,不抛出无法进行编译
        System.out.println("代码能够继续向下运行");//抛出异常后代码继续向下运行
​
    }
}

总结:在有异常的地方的方法后面加上:throws 异常类

1.5throw

抛的动作,可以跑出来一个异常的对象,可以自己造错

public class Demo1 {
    public static void main(String[] args) throws Exception  {
​
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入用户名");
            String username = scanner.next();
            if (!username.equals("庄庆友")) {
                throw new Exception("用户名不存在");//造错,如果用户名不对就报错并输出用户名错误,程序终止
            }
​
            System.out.println("请输入密码");
            int user = scanner.nextInt();
            if (!(user == 123456)) {
                throw  new Exception("密码错误");//造错,如果密码不对就报错并输出密码错误,程序终止
            }
            System.out.println("登录成功");
​
​
    }
}
​

1.6自定义异常

开发中会遇到很多的异常,但是Java中给咱们提供的异常不足以描述了。

咱们可以自己造异常

package com.qf.d_exception;
​
//抄别人的异常类   单身人士的异常类
class SinglerException  extends Exception{
    public SinglerException () {
        super();
    }
    public SinglerException (String message) {
        super(message);
    }
    
    
}
​
public class Demo7 {
    public static void main(String[] args) throws Exception {
        buy(false);
    }
    //true  是单身   false 不是单身
    
    public static void buy (boolean isSingle) throws Exception{
        if (isSingle) {
            throw new SinglerException("单身不能进店购买");
        }
        System.out.println("情侣买一送一!!!");
    }
}
​
​

day02

1.String

1.1String的两种声明方式

package com.qf.a_string;
​
public class Demo1 {
    public static void main(String[] args) {
        
        //声明的第一种方式:
        String string = "我欲乘风归去";
        System.out.println(string);
        //这第二种声明方式
        String str1 = new String("goudan");
        System.out.println(str1);
    }
}

1.2两个字符串的比较

==:比较的是内存地址

equals:先比较内存地址,地址不一样的话再比较内容

package com.qf.a_string;
​
public class Demo2 {
    public static void main(String[] args) {
        
        String str1 = "abc";
        String str2 = "abc";
        String str3 = new String("abc");
        String str4 = new String("abc");
        
        //==   比较的是内存的地址 
        System.out.println(str1 == str2);//true
        System.out.println(str1 == str3);//false
        System.out.println(str3 == str4);//false
        
        // boolean equals(Object anOnject);  比较两个字符串是否相等
        //equals  先比较的是内存地址,如果内存地址一样  肯定是一样的。如果地址不一样 再比较内容 
        //内容一样的话,也true
        System.out.println(str1.equals(str2));//true
        System.out.println(str1.equals(str3));//true
        System.out.println(str3.equals(str4));//true
        /**
         * "abc" a   "abc"b
         *   a == b  内存不一样 false
         *   继续比较内容
         *   a = {'a', 'b', 'c'}   b = {'a', 'b', 'c'};
         *   for () {
         *      if (a[i] == b[i]) {
         *          a[0] == b[0]
         *          a[1] ==b[1]
         *          a[2] == b[2]
         *      }
         *      
         *   }
         * public boolean equals(Object anObject) {
        if (this == anObject) {//比较两个内存地址是否一样
            return true;//内存地址一样的话就返回true
        }
        if (anObject instanceof String) {//true
            String anotherString = (String)anObject; 强转为字符串
                v1 = {'a', 'b', 'c'}   v2 = {'a', 'b', 'c'};
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                        
                    if (v1[i] != v2[i]) {
                        v1[0] !=v2[0]
                        v1[1] !=v2[1]
                        v1[2] !=v2[2]
                        return false;
                        }
                    i++;
                }
                return true;
            }
        }
        return false;
    }
         *   
         */
        
    }
}
​

1.3String类下面的方法

获取字符串长度 int length();

获取指定位置的字符 char charat();

获取指定字符串的下标 int indexOf();

获取指定字符串的最后一个下标 int lastIndexOf();

是否以指定字符串结尾 bollean endsWith();

判断是否为空 bollean isEmpty();

判断是否包含字符串 bollean contains();

判断两个字符串是否相等 bollean equals();

忽略大小写判断是否相等 bollean equalslgnoreCase();

将字符数组变为字符串:

String();

String();

String.valureOf();

将字符串转化为字符数组:toCharArray();

将字符替换进字符串:String replace();

以regex对字符串进行切割:String split(String regex);

截取字符串的一部分:String subString();

String subString();

将小写字母转化为大写:String toUpperCase();

将大写字母转为小写:String toLowerCase();

去除左右空格:String trim();

2.泛型

2.1为什么要用泛型

广泛的类型

在开发中对数据一致性的要求是比较高的

例如:

数组中存数据 都是同一个类I型的

int[] arr = new int[]

char[] arr = new char[]

import java.util.ArrayList;
import java.util.Scanner;
​
public class Demo1 {
    public static void main(String[] args) {
        
        int[] arr = {1,2,3,4};
        //STring类不用导包 为啥?  因为 在 java.lang包下面
        String[] strs = {"nx", "hsjj", "xnjasjn"};
        
        //数组确实可以保证数据类型一致性,但是开发不用!!!为啥?  数组的方法比较少,而且数组容量提前定好的
        //不太方便 咋办?学习集合  明天讲
         //集合的作用是和数组类似  都是容器  用来存数据的
        ArrayList list   = new ArrayList();//list  就是容器  就是用来存数据的
        list.add("狗蛋");//添加
        list.add(34);
        list.add('智');
        list.add(true);
        System.out.println(list);
        //以上代码好不好?不好!!!在开发中对数据一致性的要求是比较高的
        //获取一个数据
        String obj = (String)list.get(0);
        System.out.println(obj);
        //需要强转不好,现在有一个技术 泛型 可以保证咱们的数据一致性 针对于集合
        //ArrayList<类> 
        //<String> 告知编译器  此集合只能存放String类型的数据  一致性保证一下
        ArrayList<String>  list1 = new ArrayList<String>();
        list1.add("张三");
        list1.add("王二");
        list1.add("wangliu");
        System.out.println(list1);
        String str1 = list1.get(0);
        System.out.println(str1);
        //泛型在<类>    如果放int类型的数据===》Integer
        ArrayList<Integer> list2 = new ArrayList<Integer>();
        list2.add(23);
        //扩展:  八大基本数据类型所对应的包装类
        /**
         * byte ==> Byte
         * short===>Short
         * int===>Integer
         * long===>Long
         * boolean-===>Boolean
         * char===>Character
         * float===>Float
         * double====>Double
         */
    }
}
​

2.2自定义泛型在方法中的使用

语法格式:

public <无意义的占位符> 返回值的类型 方法的名字(参数) {
    
}

无意义的占位符:可以是任何大写字母,但是一般是T(Type)E(element)

package com.qf.b_fanxing;

public class Demo3 {
	public static void main(String[] args) {
		test();
	}
	//无参无返回值的方法  没有必要使用泛型
	public static <T>  void test () {
		System.out.println("hewllo  world");
	}
	
	//有参无返回值的方法   可以使用
	public static <T> void test (T t, T t1) {
		//t  是多个类型  操作的时候要符合数据类型相对应的操作方式
		System.out.println(t + "" + t1);
	}
	
	//无参 有返回值的    没有必要使用泛型的
	public static <T> T test1 () {
		
		return null;
	}
	
	//有参 有返回值的方fa  写起来有局限性
	public  static <T>  T test2 (T t, T t1) {
		return t;
	}
	//有参的才有一点用途
	
}

2.3泛型类

语法格式:

class 类名<无意义的占位符> {
    
}
package com.qf.b_fanxing;

class Person<T> {
	//泛型类中可以有普通的方法
	public void eat() {
		System.out.println("吃饭饭");
	}
	//带有泛型的方法   
	//public <T> void test() {一般在泛型类中的方法中不要去写<T>  因为方法的参数 根据类后面的<T> 来约束的
	public void test (T t) {
		System.out.println(t);
	}
	//静态方法  自娱自乐
	//当创建对象的时候才确定泛型类型,静态方法早于对象的创建,所以你的泛型对我是没有任何用的
	//告知程序员此处的泛型和类的泛型没有关系的
	public static <E> void test1 (E e) {
		System.out.println(e);
	}
}
public class Demo4 {
	public static void main(String[] args) {
		
		Person.test1(78);
		Person<String> strPerson = new Person<String>();
		//现在T是String  就意味者在调用test方法的时候 参数只能传String
		strPerson.test("goudan");
		//strPerson.test(89);
	}
}

2.4泛型抽象类

语法格式:

abstract class 类名<无意义的占位符> {
    
}
package com.qf.b_fanxing;

abstract class A<T> {
	abstract void test(T t);
}
//1.在继承抽象类时候  子类也必须带有和父类相同的泛型占位符
class ATest<T> extends A<T> {
	void test(T t) {
	
	} 
}
public class Demo5 {
	public static void main(String[] args) {
		ATest<Integer> aTest = new ATest();
		aTest.test(67);
	}
}

2.5泛型接口

语法格式:

interface 接口名字<无意义的占位符> {
    
}
package com.qf.b_fanxing;

interface B<T> {
	 void test(T t);
}
class BTest<T> implements B<T> {
	   public void test(T t) {
		System.out.println("xixi ");
	}
}
public class Demo6 {
	public static void main(String[] args) {
		
	}
}

day03

1.权限修饰符

权限: 针对于类,属性, 方法 在使用他们的时候是有权限的。

其实已经见过权限修饰符:

public private 默认的 (啥也不写) protected

修饰类 , 属性, 方法 等

1.1private

private 私有的

可以用来修饰属性和方法

1.私有化的所有的只能在本类中使用 其他地方用不了

1.2默认的

修饰方法和属性

1.同一个类中 可以访问的

2.在同一个包下面的 其他类可以使用

3.在不同包下面 的子类和其他类都不能使用

1.3protected

受保护的

修饰属性和方法

1.同一类中可以使用

2.同一个包下面 的不同类 可以使用

3.不同包下面的子类可以使用的

4.不同包下面的其他类不可以使用

1.4public

公开的

在本类中, 同一个包下面 不同类。 不同包下面所有的类 都可以使用的

总结:

权限修饰符当前类当前包的其他类其他包的子类其他包的其他类
private可以不可以不可以不可以
默认的可以可以不可以不可以
protected可以可以可以不可以
public可以可以可以可以

2.集合

2.1为什么要有集合

集合和数组都是可以存数据的

真是开发的时候用的是集合而不是数组

1.数组的容量是固定的

2.数组封装的方法比较少

Java有封装的集合类库,只需要实例化出来一个对象,适用对象调用方法就可以完成数据相关的操作

2.2集合结构

interface Collection<E>java中集合的总接口

List<E> Collection的子接口,特征:存放数据是有序的,可以重复的

ArrayList<E>List的实现类,里面写好了List接口所有的抽象方法,功能也写好了,底层是数组

LinkedList<E>List的实现类,里面有自己独有的方法,底层是链表

Set<E> Collection的子接口,特征:存放数据是无序的不可重复的

HashSet<E>Set的实现类,底层是Hash算法

TreeSet<E>Set的实现类,底层是二叉树

2.3Collection接口

Collection下面的方法:
    增:
    添加数据:add();
	将一个集合添加到另一个集合中:addAll();
	删:
    删除指定的元素:remove();
	删除集合中所有的另一个集合的元素:removeAll();
	清空集合:clear();
	查:
    集合中元素的个数:size();
	将集合转化为数组:toArray();
	在集合中是否包含:contions();
	判断一个集合是否是另一个集合的子集:contionsAll();
	判断是否为空:isEmpty();
package com.qf.c_collection;

import java.util.ArrayList;
import java.util.Collection;



public class Demo1 {
	public static void main(String[] args) {
		//父类的引用指向了子类的对象,意味着 对象只能调用父类的方法     
		//对象不能调用子类独有的方法  只能调用重写的方法
		//Collection 所有的抽象方法都被ArrayList  重写了
		Collection<String> collection = new ArrayList<String>();//容器  只能放String类型的数据
		collection.add("红旗渠");
		collection.add("散花");
		collection.add("黄鹤楼");
		System.out.println(collection);//[红旗渠, 散花, 黄鹤楼]
		Collection<String> collection1 = new ArrayList<String>();//容器  只能放String类型的数据
		collection1.add("舍得");
		collection1.add("茅台");
		collection1.add("牛栏山");
		System.out.println(collection1);
		collection.addAll(collection1);//将collection1这个集合添加到collection中
		System.out.println(collection);//[红旗渠, 散花, 黄鹤楼, 舍得, 茅台, 牛栏山]
		
//		Collection<Integer> collection2 = new ArrayList<Integer>();//容器  只能放String类型的数据
//		collection2.add(1);
//		collection2.add(2);
//		collection2.add(3);
//		
//		collection.addAll(collection2);
		System.out.println(collection.remove("舍得"));//删除指定的数据
		System.out.println(collection);//删除之后的结果 
		//[红旗渠, 散花, 黄鹤楼, 茅台, 牛栏山]
		//System.out.println(collection.remove("舍得"));
		Collection<String> collection3 = new ArrayList<String>();//容器  只能放String类型的数据
		collection3.add("舍得");
		collection3.add("茅台");
		collection3.add("牛栏山");
		collection3.add("红花郎");
		System.out.println(collection3);//[舍得, 茅台, 牛栏山, 红花郎]
		collection.removeAll(collection3);//删除指定集合中包含的所有此集合的元素
		//在collection 删除collection3 中包含的元素
		System.out.println(collection);//[红旗渠, 散花, 黄鹤楼]
		collection.clear();
		System.out.println(collection);//[]
		
		
		
	}
}

2.4遍历集合中的数据

3种 1.使用for循环 2.使用增强for循环【重点】 3.使用迭代器【重点】

2.4.1使用for循环

package com.qf.c_collection;

import java.util.ArrayList;
import java.util.Collection;

public class Demo2 {
	public static void main(String[] args) {
		Collection<Character> list =  new ArrayList<Character>();
		list.add('a');
		list.add('b');
		list.add('c');
		System.out.println(list);//[a, b, c]
		//for循环遍历
		//将集合转为数组 然后再遍历
		Object[] objs = list.toArray();
		for (int i = 0; i < objs.length; i++) {
			System.out.println(objs[i]);
		}
		
	}
}

2.4.2使用增强for

语法格式:

for (集合或数组的数据类型  临时变量名字 : 集合或者数组) {
    
}
//将集合中的元素依次赋值给临时变量,输出的时候直接输出临时变量就可以
public class Demo1 {
    public static void main(String[] args) throws Exception  {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("dafsd");
        arrayList.add("fadsfas");
        arrayList.add("fadsfasdaas");
        arrayList.add("fadsfadsdas");
        for (String arr : arrayList) {//增强for循环
            System.out.println(arr);
        }
    }
}

2.4.3迭代器

package com.qf.c_collection;

import java.util.ArrayList;
import java.util.Collection;

public class Demo3 {
	public static void main(String[] args) {
		Collection<String> liStrings = new ArrayList<String>();
		liStrings.add("张三");
		liStrings.add("狗蛋");
		liStrings.add("老邢");
		System.out.println(liStrings);
		//使用增强for循环遍历数据
		for (String s : liStrings) {
			System.out.println(s);
		}
		
	}
}

2.5List接口

Collection是List接口的父接口

为什么开发用List而不用Collection

List接口下面有自己独有的方法,子接口的功能比父接口的功能全

子接口不但重写了父类接口所有的方法,而且加了自己独有的方法

所以开发用List

List接口储存数据的时候	有序的	可以重复的
    增:
    在指定索引位置的下标插入一个数据:add();
	在指定下标的位置插入另一个集合:addAll();
	删:
    通过索引删除数据,返回的是被删除的元素:remove();
	改:
    指定下标的元素被别的元素替代,返回的是被替代的元素:set();
	查:
    size();
	toArry();
	contians();
	isEmpty();
	获取指定下标的元素:get();
	获取指定元素的下标:indexOf();
	获取指定元素最后一次出现的位置:lastindexOf();
	截取集合中的一段:subList();
	
import java.util.ArrayList;
import java.util.List;

public class Demo1 {
	public static void main(String[] args) {
		
		List<String> list = new ArrayList<String>();
		System.out.println(list);
		list.add("狗蛋");
		list.add("张三");
		list.add("李四");
		list.add("张三");
		list.add("李四");
		list.add("李四");
		list.add("张三");
		System.out.println(list);//[狗蛋, 张三, 李四]
		
		list.add(1, "王五");//在指定的下标的位置上面添加一个元素
		System.out.println(list);//[狗蛋, 王五, 张三, 李四]
		
		
		//通过元素删除
		System.out.println(list.remove("二蛋"));//false
		//通过索引下标删除
		System.out.println(list.remove(0));//狗蛋
		//
		System.out.println(list);//被删除之后的集合元素
		//[王五, 张三, 李四]
		System.out.println(list.set(1, "王八"));//返回值是被替换的元素
		System.out.println(list);//[王五, 王八, 李四]
		
		System.out.println(list.get(2));//李四
		
		System.out.println(list.indexOf("王博"));//-1
		System.out.println(list.indexOf("王八"));//1
		System.out.println(list.lastIndexOf("张三"));//6
		
		
		//list = [王五, 王八, 李四, 张三, 李四, 李四, 张三]
		System.out.println(list.subList(2, 4));//[李四, 张三]
		
		
		
	}
}

2.6接口List数据遍历

for循环

增强for循环

迭代器

List集合不用转为数组就能使用for循环进行遍历

import java.util.ArrayList;
import java.util.List;

public class Demo2 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		
		list.add("狗蛋");
		list.add("张三");
		list.add("李四");
		list.add("张三");
		list.add("李四");
		list.add("李四");
		list.add("张三");
		System.out.println(list);//[狗蛋, 张三, 李四]
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
	}
}

2.6.1迭代器

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class Demo4 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		
		list.add("狗蛋");
		list.add("张三");
		list.add("李四");
		list.add("张三");
		list.add("李四");
		list.add("李四");
		list.add("张三");
		
//		ListIterator<String> listIterator = list.listIterator();
//		while (listIterator.hasNext()) {
//			System.out.println(listIterator.next());
//		}
//		//循环结束代码走到这一步 咱们的光标在  最后一个位置
//		System.out.println("=========");
//		//上一个是否有元素
//		while (listIterator.hasPrevious()) {
//			//返回上一个元素并且 光标向上一个
//			System.out.println(listIterator.previous());
//		}
		
		ListIterator<String> listIterator = list.listIterator(list.size());
		while (listIterator.hasPrevious()) {
			System.out.println(listIterator.previous());
		}
	}
}

List集合的迭代器

可以从前往后遍历,也可以从后往前遍历

day04

1.List集合中存自定义对象

集合容器中存数据的时候,可以存字符串整型等,也可以存储对象,集合中带有泛型,是一个类

存储对象的时候,为了方便获取对象数据,所以要重写toString方法

package com.qf.b_list;

import java.util.ArrayList;
import java.util.List;

class Person {
	private String name;
	private int age;
	
	public Person() {
		
	}
	
	public Person(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;
	}

	@Override//重写的toString方法    Object类
	//将内存地址 转为一个字符串表示的形式 可以看到打印的数据  不再是一个内存地址了
	//而是一个字符串了
	public String toString() {
		return "[name:" + name + ", age:" + age + "]";
	}
	
	
}
public class Demo1 {
	public static void main(String[] args) {
		List<Person> persons = new ArrayList<Person>();
		Person person1 = new Person("狗蛋", 24);
		Person person2 = new Person("张三", 14);
		Person person3 = new Person("王五", 34);
		persons.add(person1);
		persons.add(person2);
		persons.add(person3);
		System.out.println(persons);
		//以上在存数据
		//可以取数据
//		System.out.println(persons.get(0));//获取的是集合中第一个对象
//		System.out.println(persons.get(1));
//		System.out.println(persons.get(2));
//		
//		//想只把狗蛋取出来
//		//先取出来第一个person对象
//		System.out.println(persons.get(0).getName());
		for (Person person : persons) {
			System.out.println(person.getName() + ":" + person.getAge());
		}
		
		
	}
}

day05

1.Object类

Object类是所有类的基类,父类

public String toString()

返回对象的字符串表现形式,一般来说toString返回一个“textually“这个对象的字符串,结果应该是一个简明扼要的表达,容易让人阅读,建议所有子类重写此方法

package com.qf.a_object;

class Person {
	String name;
	int age;
	
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
	
	
}
public class Demo1 {
	public static void main(String[] args) {
		Object object = new Object();
		Object object2 = new Object();
		
		System.out.println(object);
//		该toString类方法Object返回一个由其中的对象是一个实例,
		//该符号字符`的类的名称的字符串@ ”和对象的哈希码的无符号的十六进制表示。 换句话说,这个方法返回一个等于下列值的字符串:
//
//		 getClass().getName() + '@' + Integer.toHexString(hashCode())
		System.out.println(object.toString());//java.lang.Object@15db9742
		
		Person person = new Person();
		System.out.println(person);
	}
}
public bollean equals(Object obj)

指示一些其他对象与此对象是否相等,判断两个对象是否相等

public boolean equals(Object obj) {
     return (this == obj);
 }

==:比较的是内存地址

object1.equals(object2)

为啥String类下面equals如果内容一样的可以返回true?当父类的需求满足不了子类的需求

String类重写了父类的equals方法

class Student {
	String name;
	int age;
	
	public Student(String name, int age) {
		
		this.name = name;
		this.age = age;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {//如果内存地址一样 就返回true
			return true;
		}
		//如果内存地址不一样,但是内容一样咋写
		//equals(Object obj)   Object obj = student2;//向上转型
		//student1.equals(student2)
		//obj instanceof Student     
		if (obj instanceof Student) {// student2 instanceof Student true
			Student stu = (Student)obj;//向下转型
			
			//student2===>stu
			// student1.name.equals(student2.name) true && student1.age == student2.age
			return this.name.equals(stu.name) && this.age == stu.age;
		}
		
		return false;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	
}
public class Demo3 {
	public static void main(String[] args) {
		Student student1 = new Student("土豆", 12);
		Student student2 = new Student("土豆", 12);
		System.out.println(student1.equals(student2));//因为Object类是Student的父类
		//以上是false, 但是真实的开发的时候,关注的是内容 而不是地址
		//只要内容一样也得给我true。 咋办?重写eqauls方法
	}
}
public int hashCode()

返回的哈希码值,支持这种方法是为了散列表,如HashMap提供的那样

在Object类中,将十六进制的内存地址转为十进制的值,就叫hash值

如果内存地址不一样,那么哈希也是不一样的

hashCode的总合同是:

如果根据equals(Object)方法两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果

class Man {
	int id;
	String name;
	public Man(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj instanceof Man) {
			Man man1 = (Man)obj;
			return man1.id == this.id && man1.name.equals(this.name);
		}
		return false;
	}
	@Override
	public int hashCode() {
		
		return name.hashCode();
	}
	
	
	
}
public class Demo6 {
	public static void main(String[] args) {
		//比较两个对象的而内容是否一致
		Man  man1 = new Man(2, "蔡徐坤");
		Man  man2 = new Man(2, "蔡徐坤");
		System.out.println(man1.equals(man2));//true
		
		//如果根据`equals(Object)`方法两个对象相等,
		//则在两个对象中的每个对象上调用`hashCode`方法必须产生相同的整数结果
		System.out.println(man1.hashCode());
		System.out.println(man2.hashCode());
		
		//只能重写hashCode方法 不要再使用Object类下面hashCode
		
	}
}

由此可得出结论,重写equals方法时,通常也要重写hashCode方法,一边维护hashCode方法的通用合同,该方法规定相等的对象必须具有相等的哈希码值

class Man {
	int id;
	String name;
	public Man(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Man other = (Man) obj;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
	
	
	
}
public class Demo6 {
	public static void main(String[] args) {
		//比较两个对象的而内容是否一致
		Man  man1 = new Man(2, "蔡徐坤");
		Man  man2 = new Man(2, "蔡徐坤");
		System.out.println(man1.equals(man2));//true
		
		//如果根据`equals(Object)`方法两个对象相等,
		//则在两个对象中的每个对象上调用`hashCode`方法必须产生相同的整数结果
		System.out.println(man1.hashCode());
		System.out.println(man2.hashCode());
		
		//只能重写hashCode方法 不要再使用Object类下面hashCode
		
	}
}

2.Set集合

Set集合也是用来存数据的

Set集合父接口为Collection接口

Set存数据的时候是无序的不可重复的

Set接口下面有两个实现类:

HashSet:底层是hash值进行储存的,如果hash纸一样的就无法存到集合中

TreeSet:底层是二叉树,对存入的数据进行自然排序

package com.qf.b_hashSet;

import java.util.HashSet;
import java.util.Set;

class Person {
	int id;
	String name;
	public Person(int id, String name) {
		
		this.id = id;
		this.name = name;
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
	
}
public class Demo2 {
	public static void main(String[] args) {
		
		Set<Person> set = new HashSet<Person>();
		Person person1 = new Person(1, "老邢");
		Person person2 = new Person(2, "骚磊");
		Person person3 = new Person(1, "老邢");
		set.add(person1);
		set.add(person2);
		set.add(person3);
		System.out.println(set);
		//现在存了三个对象。感觉可以吗?不可以  关注是内容!!!咋干掉?
		
		//重写equlas和hashCode方法
	}
}

总结: 如果将对象存入到hashSet中的时候,必须重写当前类的equals和hashCode方法 为了保证对象的内容不重复。

HashSet的底层是HashMap JDK1.8 数组 + 链表 + 红黑树 三个组成

2.1TreeSet

也是Set的实现类,可以保证数据唯一性,储存也是无序的,同时会对存入的数据进行自然排序

2.2TreeSet存自定义的对象

存对象的时候需要在类的实现Comparable这个接口。该接口对实现它的每个类的对象强加一个整体排序。 这个排序被称为类的自然排序 ,类的compareTo方法被称为其自然比较方法

int compareTo(T o)

将此对象与指定的对象进行比较以进行排序。

返回一个负整数,零或正整数,因为该对象小于,等于或大于指定对象。

person1.compareTo(person2)

如果返回值是负数, 就证明 person1小于 person2 排序 person1 排在person2前面

如果返回值是0,就证明相等,不存了

如果是个正数,就证明大于 person2 排在person1的前面

package com.qf.c_treeset;

import java.util.Set;
import java.util.TreeSet;

class Person implements Comparable<Person>{
	String name;
	int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	@Override
	public int compareTo(Person o) {
		// TODO Auto-generated method stub
		//1. this 就是狗蛋   o也是狗蛋
		//2. this 潘周丹     o狗蛋       【 潘周丹  狗蛋】
		//3. this 旺财  o狗蛋    【潘周丹  狗蛋  旺财 】
		//4.this erdsan  o狗蛋  【潘周丹  狗蛋  旺财 】
		int num  = this.age - o.age;
		return num;
		
		//2.[潘周丹 狗蛋]
		//3.[旺财 狗蛋]
		//4.[潘周丹  旺财erdan 狗蛋]
	}
	
}
public class Demo2 {
	public static void main(String[] args) {
		Set<Person> set = new TreeSet<Person>();
		set.add(new Person("狗蛋", 24));//这行开始报错
		set.add(new Person("潘周丹", 21));
		set.add(new Person("旺财", 23));
		set.add(new Person("erdsan", 24));
		//Exception in thread "main" java.lang.ClassCastException: 
		//com.qf.c_treeset.Person cannot be cast to java.lang.Comparable
		System.out.println(set);
		//按照age进行排序
		
	}
}
//按照年龄进行排序
package com.qf.c_treeset;

import java.util.Set;
import java.util.TreeSet;

//先按照年龄 如果年龄 再字符串比较
class Student implements Comparable<Student>{
	String name;
	
	int age;

	public Student(String name, int age) {
		
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int compareTo(Student o) {
		int num = this.age - o.age;
		if (num == 0) {//当 age  相等的时候
			int num1 = this.name.compareTo(o.name);
			return num1;
		}
		return num;
	}
	
	
}
public class Demo3 {
	public static void main(String[] args) {
		Set<Student> set = new TreeSet<Student>();
		set.add(new Student("b", 65));
		set.add(new Student("d", 35));
		set.add(new Student("c", 25));
		set.add(new Student("a", 35));
		set.add(new Student("浩正", 35));
		System.out.println(set);
		
		
	}
}

通过查阅API我们得知TreeSet集合是基于TreeMap的实现,而TreeMap是基于二叉树(红黑树)结构,也就是说TreeSet集合的底层使用的二叉树(红黑树)结构。

树结构:它也是数据结构中的一种。在计算机领域中树结构指的是倒立的树。

树结构存储的数据,每个数据也需要节点来保存。

而TreeSet集合底层是二叉树的数据结构,什么是二叉树呢?

二叉树:每个节点的下面最多只能有2个子节点。

说明:最多表示一个节点下面可以有两个子节点或者一个子节点或者没有子节点。

在二叉树的根节点左侧的节点称为左子树,在根节点的右侧的节点称为右子树。

既然已经得知TreeSet集合底层是二叉树,那么二叉树是怎样存储数据的呢?是怎样保证存储的数据唯一并有序的呢?

二叉树的存储流程:

当存储一个元素的时候,如果是树的第一个元素,这个元素就作为根节点。

如果不是第一个元素,那么就拿要存储的元素与根节点进行比较大小:

大于根元素:就将要存储的元素放到根节点的右侧,作为右叶子节点。

等于根元素:丢弃。

小于根元素:就将要存储的元素放到根节点的左侧,作为左叶子节点。

总结:二叉树是通过比较大小来保证元素唯一和排序的。 20 10 31 5 13 23 51

关于TreeSet在存储数据的时候,会有一个排序的问题u,。使用一个接口叫Comparable这个接口

咱们还可以使用另外一种方式进行排序。叫比较器的写法

TreeSet(Comparator<? super E> comparator)

构造一个新的,空的树集,根据指定的比较器进行排序。

package com.qf.c_treeset;

import java.util.Comparator;
import java.util.TreeSet;

class Emp {
	String name;
	int age;
	public Emp(String name, int age) {
		
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Emp [name=" + name + ", age=" + age + "]";
	}
	
}
class MyComparator implements Comparator<Emp> {

	@Override
	public int compare(Emp o1, Emp o2) {
		// TODO Auto-generated method stub
		int num1  = o2.age - o1.age;
		return num1;
	}
	
}
public class Demo4 {
	public static void main(String[] args) {
		//借助于有参的构造方法
		//TreeSet(Comparator<? super E> comparator)
		//构造一个新的,空的树集,根据指定的比较器进行排序。
		TreeSet<Emp> emps = new TreeSet<Emp>(new MyComparator());
		emps.add(new Emp("狗蛋", 23));
		emps.add(new Emp("狗蛋1", 22));
		emps.add(new Emp("狗蛋2", 24));
		emps.add(new Emp("狗蛋3", 21));
		System.out.println(emps);
	}
}

3.匿名内部类

为了减少代码量

3.1基于抽象类匿名内部类

package com.qf.d_niming;

abstract class Person {
	public abstract void eat();
}
//class Man extends Person {
//
//	@Override
//	public void eat() {
//		// TODO Auto-generated method stub
//		
//	}
//	
//}
public class Demo1 {
	public static void main(String[] args) {
//		Person person = new Person() {
//			@Override
//			public void eat() {
//				// TODO Auto-generated method stub
//				System.out.println("吃饭");
//			}
//		};
//		person.eat();
		
		new Person() {
			
			@Override
			public void eat() {
				// TODO Auto-generated method stub
				System.out.println("吃汉堡");
			}
		}.eat();
		
	}
}

不用再创建类去继承抽象类就可以直接重写抽象类的方法并调用

真实开发的用法:一个方法的参数是一个抽象类

package com.qf.d_niming;

abstract class Student {
	public abstract void sleep();
	
}

public class Demo2 {
	public static void main(String[] args) {
		//test方法参数是抽象类的对象
		test(new Student() {
			
			@Override
			public void sleep() {
				// TODO Auto-generated method stub
				System.out.println("睡得老想了");
			}
		});
	}
	public static void test (Student stu) {
		stu.sleep();
	}
}

3.2基于接口的匿名内部类

package com.qf.d_niming;

interface Dog {
	void lookHome();
}
public class Demo3 {
	public static void main(String[] args) {
		new Dog() {
			
			@Override
			public void lookHome() {
				// TODO Auto-generated method stub
				System.out.println("看家比较负责任");
			}
		}.lookHome();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值