# day01
一:基本操作
package _01.java基本操作; /** * 文档注释 */ public class _01Alls { public static void main(String[] args){ /* * 数据类型: * 数值型: * 整数:byte(1), short(2), int(4), long(8) * 浮点:float(4), double(8) * 字符串:char(2) * 布尔 :boolean(1) * * String:双引号(单引号只能放一个) * * 类型转换: * 手动转换: * 1. 不能直接把一个大的类型赋值给小的类型 * 2. 强制类型转换后才可赋值:byte b (byte)100; * 自动转换: * 1. 运算时,两端类型需要一致 * 2. 如果是数值运算,会把小的转换为大的类型 * 3. JVM 运算时,最小识别类型时 int (byte,short char 会自动提升为 int 类型) * * 自增与自减:(正在运算时不会计算,但是运算结束后会加上,且不会叠加,++几次就是几) * 注:a++ / a-- 参与运算时使用初始值 * ++a / --a 参与运算时使用的是自增后或自减后的值 * * 三元运算: * 接收值 = 逻辑表达式 ?表达式1(true) : 表达式2(false) * * 逻辑运算: * ^ : 相同返回 false, 不同返回 true * && / || : 一旦一方成立,后面不再执行 * * switch 语句: * 1. 完整写法: * switch(整型表达式){ * case 值1 : { * 返回结果; * }break; * case 值2 : { * 返回结果; * }break; * default : 没有条件满足则执行此语句; * } * 2. 简写: * switch(整型表达式){ * case 值1 : 返回结果;break; * case 值2 : 返回结果;break; * case 值3 : 返回结果;break; * default : 没有条件满足则执行此语句; * } * * do while(先执行一次代码块,再进行判断): * do{ * 代码块; * }while(表达式); * * for 循环:( 可以给循环起 别名:outter : for(..){...} ) * for(int num = 1; num <= 10; num++){ * 代码块; * } * foreach: * for(数据类型 i : 数组){ * 代码块; * } * * 终止: * 1. break : 跳出循环, 后续同级代码继续执行 * 2. return : 跳出循环, 后续不执行,包括同层级代码 * * 方法: * 1. 声明到 class 中 * 2. 如果一个方法之前有 static 那么这个方法也需要加 static * 3. void : 这个参数意思是返回空, 但是如果有返回值的话, void需要改成返回值的数据类型 * 方法重载: * - 在同一个类中,允许两个方法名重复,但前提是两个方法的参数(类型也可以一致)不能一致 * * 可变参数: * 1. 数组: void a(int[] arg){xxx} * 2. 可变: void a(int ...arg){xxx} * */ // 变量声明 int a = 10; int b = 20; // // // 打印 System.out.println('a'); System.out.println(true ^ false); // true int num = 100; if(num == 100){ System.out.println("true"); } boolean s = true; while(s){ System.out.println('1'); } } }
二:数组
package _01.java基本操作; public class Array { public static void main(String[] args) { // 数组写法: // 要存放的数据类型[] 数组名 = new 要存放的数据类型[] {存放的数据内容} // 简写:int[] array = {1,2,3} // int[] array = new int[] {1,2,3}; // System.out.println(array[0]); /* // 1. 静态定义数组 // 定义一个数组 String[] strInfo; // 初始化数组 strInfo = new String[] {"q","w"}; System.out.println(strInfo[1]); String l = "["; for(int i=0; i<strInfo.length; i++){ l+=strInfo[i]+','; } String res = l+"]"; System.out.println(res); */ // 2. 动态定义数组 // String[] all = new String[100]; // all[0] = "Hello"; // System.out.println(all[0]); // 3. 二维数组 // 写法:int[][] Arrays = new int[][] {arr1,arr2,arr3} // 获取: int[] arr1 = {1,2,3}; int[] arr2 = {4,5,6}; int[][] arr = {arr1,arr2}; for(int i : arr1){ System.out.println(i); } /* for(int i = 0; i<arr.length; i++){ int[] now_arr = arr[i]; for(int j = 0; j < now_arr.length; j++){ System.out.println(now_arr[j]); } } */ } }
三:面向对象
package _02.java面向对象; public class _02SomeInfo { String name; int age; _02SomeInfo(String name){ this.name = name; } _02SomeInfo(String name, int age){ this(name); this.age = age; } void run(){ System.out.println(name+" is Run.."); } void eat(String food){ System.out.println(name+" want Eat " +food); } public static void main(String[] args){ /* _02SomeInfo info = new _02SomeInfo(); info.name = "q"; info.age = 11; info.run(); info.eat("apple"); */ _02SomeInfo info = new _02SomeInfo("q",11); info.run(); info.eat("apple"); } /* * 虚拟机栈:(每个函数从调用到执行结束,就是对应一个栈帧的入栈和出栈) * 当执行一个方法时,就会为这个函数创建一个栈帧,并加入虚拟机栈。 * * 堆:被所有线程共享的一块区域,在虚拟机启动时创建,所有的对象实例及数组都在堆上分配 * (使用 new 关键字表示在堆中开辟一块新的空间) * * 属性概念: * - 有 getter/setter 方法的才是属性,否则是 字段或成员变量。 * * 构造器: * 1. 作用: * - 创建对象,必须和new一起使用。 * - 完成对象的初始操作。 * 2. 特点: * - 构造器的名称和当前类名是一样的。 * - 禁止有返回类型,不能使用void作为返回值。 * - 在构造器中不能使用 return * - 但是构造器有返回值(返回值时内存地址) * 3. 默认构造器特点: * - 符合构造器特点。 * - 无参数。 * - 如果类中有 public 装饰,那么构造器也会有public,否则无。 * 4. 自定义构造器: * - 使用: * User(){ * 代码块; * } * - 构造器重载: * User(String name){ * Myname = name; * } * User(String name, int age){ * Myname = name; * Myage = age; * } * * static 修饰符: * 1. 概念: * - 如果在字段或方法面添加了 static, 那么它的字段或方法就属于类(类成员),没有添加则是 实例成员 * 2. 特点: * - static装饰的内容是随着类的加载而加载的。 * - static装饰的内容,优先于对象的存在。 * - static装饰的内容,被该类型的所有对象共享。 * - static装饰的内容,可以直接使用类名调用。 * 3. 类成员和实例成员的访问: * - 在 static 方法中只能调用 static 成员 * - 非 static 方法,两者都可以访问。 * 4. 注: * - 方法中不能定义以 static装饰的变量。 * * 封装: * 1. 访问修饰符: * - private : 表示私有(类访问权限),且只能在类中才有访问权限。 * - protected : 表示子类访问权限,同包中可以访问,不同包中不能访问,同包不同类不能访问,继承可以访问。 * - public : 表示全局,可以在项目中任何地方使用。 * - 默认 : 表示包访问权限,同一类中可以访问,同一包,不同类可以访问,不同包不能访问。 * * this: * 1. 解决成员变量和参数问题。 * 2. static 不能和 this 一起使用。 * 3. 构造器的重载互调: * - 在一个构造器中调用另一个构造器: * - this(xx) // 必须写在第一行。 * User(String name){ * this.name = name; * } * User(String name, int age){ * this(name); * this.age = age; * } * */ }
# day02
一. 封装:(提供外部能够访问的接口)
1. 良好的封装能够减少耦合。
2. 类内部的结构可以自由修改。
3. 可以对成员进行更精确的控制。
4. 隐藏信息,实现细节。
二. 继承:
01. 使用 extends 来继承父类(extends 后面跟继承类):
- public class Student extends Person{}
02. 修饰符继承:
- public 子类都可以继承。
- protected 子类可以继承,不同包也可以继承。
- private 只能在本类中可以使用,子类无法使用。
- 默认 同一包可以继承,不同包不能继承。
注:父类的构造器是无法继承的。
2. 覆盖原则:
- 方法名和参数一致。
- 子类方法的返回值类型和父类方法返回值类型一致。
- 子类方法的访问权限比父类要大或者相同。
3. 判断该方法是否是覆盖方法(如果不是则会报错)。
- 在子类中将覆盖方法上方加上 @Override 。
4. 继承super关键字:
- 凡是子类的构造方法中就会有 super();
- super 代表的父类对象。
- super 构造方法必须要放到第一行。
Foo(xx,xx){ super(xx,xx); this.xx = xx; }
三. 多态:
1. 特点:
- 子类对象赋值给父类类型。
- Animal cat = new Cat();
- 运行时,表现的是子类的特征(先去找子类)。
2. 使用:
class Animal{ static void eat(){ System.out.println('animal') } } class Dog extends Animal{ static void eat(){ System.out.println('dog') } } class Cat extends Animal{
static void eat(){ System.out.println('cat') } } class Person{ - 在接收值得时候只需要当作类对象接收,这样就不需要考虑是哪个类对象的实例了。 void get(Animal anim){ anim.eat(); } } Dog dog = new Dog(); Cat cat = new Cat(); Person per = new Person(); per.get(dog); per.get(cat);
四. instanceof 关键字:
- 判断一个对象是否是指定的类,如果是返回true,否则false。
if(anim instanceof Dog){ // 类的强制类型转换: 把父类对象赋值给子类对象。 Dog dog = (Dog)anim; }
- 注:字段不存在多态。
五. 局部代码块和初始化代码块:
使用: 在类中或方法中,使用{}括起来。
1. 局部代码块 : 直接定义在方法内部的代码块。
2. 初始化代码块: 直接在类当中定义的代码块(运行时还是要放在构造方法中)。
3. 静态代码块 : 在初始化代码块前面加 static。
- 在加载字节码的时候自动调用。
- 在主方法之前执行,且只执行一次。
六:组合关系:
1. 类中的字段是 另一个 "类" 类型, 依赖其它的类。
- Person per;
2. 类在第一次使用该类对象的时候就 加载到 JVM 中,
只加载一次,下一次就直接从内存中使用。
七: final 关键字:
1. 只可用,不可修改,保证数据的安全。
2. 可以修饰:
- 字段:不能修改该字段。
- 方法:子类就不能覆盖该方法。
- 类 :该类不能被其它类继承(不能有子类)。
3. 修饰字段时,字段是没有初始值,须手动设置。
4. 修饰变量,就代表是一个常量(因为无法修改)。 命名:所有的字母都可大写。
- final int MAX_VALUE
5. 可以带局部代码块中使用。
6. 修饰基本数据类型: 值不能改。 final int a = 1;
修饰引用数据类型: 地址不能改。 final Person p = new Person();
八. 单例模式:
class ToolUtil{ // 1. 必须要在类中创建一个对象。 private static ToolUtil instance = new ToolUtil(); // 2. 私有化自己的构造器,防止外界通过构造器创建新的对象。 private ToolUtil(){} // 3. 给外界提供一个接口,拿到已经创建好的对象。 static public ToolUtil getInstance(){ return instance; } }
九. 包装类:
byte - Byte short - Short int - Integer long - Long float - Float double - Double char - Character boolean - Boolean
1. 自动装箱与自动拆箱。
- Integer i = 20; (装)
- int i1 = i; (拆)
十. 抽象方法:
1. 使用:在方法前加一个关键字 abstract
2. 特点:
- 子类必须覆盖此方法。
- 抽象方法没有方法体(也就是没有{})。
- 抽象方法必须要定义在抽象类中 或 接口中(在类前面添加一个abstract 就是抽象类)
- 抽象方法不能与 private, final, static 同时装饰。
十一. 抽象类:
注:必须要有子类。
定义: 在类前面添加一个 abstract 就是抽象类。
1. 不能直接创建对象。
2. 可以有抽象方法,也可有非抽象方法。
十二. 接口:
1. 接口中没有构造器,不能创建对象。
2. 接口中定义的变量都是全局的静态常量。
- String name = 'q'; --> public static final String name;
3. 接口当中定义的方法都是公共的抽象的方法。
- void transData(); --> public abstract void transData();
4. 接口可以多继承。
5. 接口的使用:
- 定义接口: interface 接口类名{} - 实现接口: class 类名 implements 接口类名{} interface Iwalkable{ void walk(); // 编译时: public abstract void walk(); } interface Iswimable{ void swim(); } interface Iqable extends Iwalkable, Iswimable{ // 接口的多继承 } // 实现接口 // 同时也可以继承类(只能继承一个类) class Cat extends Animal implements Iwalkable{ // 1. 需要 implements 关键字后面跟接口 // 2. 必须加 public 因为接口类的方法在编译的时候是由 public装饰的。 // 而子类权限必须要比父类大或者一致才可。 public void walk(){} } // main 中: Iwalkable cat = new Cat(); // 面向接口编程 cat.walk(); // 多态运行时表现的还是子类特征(编译时看左边,运行时,看右边)
十三. 抽象类 和 接口类:
1. 相同点:
- 都是被其他类实现或被继承。
- 都不能实例化。
- 都可以定义抽象方法,定义的抽象方法子类必须覆盖。
2. 不同点:
- 接口类没有构造器,抽象类有构造器。
- 抽象类可以包含普通方法和抽象方法,
接口类中只能有抽象方法,不能有普通方法(方法不能加{})。
- 接口类中默认成员变量 : public static final 变量; (静态变量)。
- 抽象类:默认权限。
- 接口类中方法: public abstract 方法名;
十四. 内部类 (外部类修饰符只能有 public 或 不加(默认), 内部可随意装饰):
1. 实例内部类(是属于对象的内部类,且不被 static 装饰):
- 必须创建外部类才能使用 内部类。
- 内部类可以访问外部类成员。
- 内部类中不能有静态成员。
- 外部类不能直接访问内部类成员。
class Outter{ String name = '1'; class Inner(){ String name = '2'; void test(){ String name = '3'; System.out.println(name); // 3 System.out.println(this.name); // 2 System.out.println(Outter.this.name); // 1 } } } // main 中: // 创建内部类。 Outter out = new Outter(); Outter.Inner in = out.new Inner(); // 调用内部类方法。 in.test();
2. 静态内部类:
- 静态内部类是不需要创建外部对象。
Outter.Inner in = new Outter.Inner();
- 静态内部类中,是没有外部类引用(由于static装饰,没有创建外部类对象地址,所以没有被外部类引用)。
- 静态内部类,是可以访问外部类的静态成员的。
- 访问静态内部类中的静态成员: Outter.Inner.h;
class Outter(){ static String name = "q"; static class Inner(){ String h = "hello"; void test(){ System.out.println(name); System.out.println(new Outter().age); } } } // main : // 创建静态内部类。 Outter.Inner in = new Outter.Inner(); in.test(); // 访问静态内部类中的静态成员 System.out.println(Outter.Inner.h);
3. 局部内部类(定义在方法中的内部类):
- 不能使用装饰。
- 局部内部类只能在定义的方法中使用。
- 不能包含静态变量。
- 可以包含局部变量,使用局部变量的本质是 final (常量)。
class Outter{ void q(){ // final 可以不写,默认编译时会自动加上(1.8之后) final String name = "q"; class Inner{ void test(){ System.out.println(name); } } Inner in = new Inner(); in.test(); } } // main 中: new Outter().q();
4. 匿名内部类:
- 必须有父类,或者实现了接口。
- 没有名字的局部内部类。
- 没有构造器。
使用方法:
new 父类的构造器 或 接口 (){
public void test(){
// 代码块...
}
}
十五. 枚举:
- 枚举: 表示一个事件固定状态。
- java 枚举 : 一个特殊的类,多个常量对象的集合。
- 格式:
[修饰符] enum 枚举名称{ 常量1,常量2... }
enum SEX{ NAN,NV }
十六. 常用工具类:
1. Scanner 输入键盘信息:
import java.util.Scanner; Scanner sc = new Scanner(System.in); // 会在控制台等待键盘输入。 String str = sc.nexLine(); // 字符
2. 数据的拷贝:
- 参数:
arraycopy(源数组, 源数组中起始位置, 目标数组, 目标数组中起始位置, 要复制的数据量)
- 使用:
int[] src = {1,2,3}; int[] desc = new int[5]; System.arraycopy(src, 2, desc, 0, 2);
3. 计算时间 (其它查文档):
long time = System.currentTimeMillis();
4. Math 数学类:
// 求最大值 int res = Math.max(10, 20); // 求最小值 int res = Math.min(1, 2); // 返回 0 - 1 之间随机数 Math.random(); // 返回 0 - 100 随机整数 int res = (int) (Math.random*100); // 开根 double res = Math.sqrt(4); // 数字精度计算 import java.math.BigDecimal BigDecimal num1 = new BigDecimal("0.9"); BigDecimal num2 = new BigDecimal("0.1"); System.out.println(num1.add(num2));
十七. 字符串:
1. 空值:
- String str = null; 还未初始化,没有分配内存空间。
- String str = ""; 已经创建对象,分配了内存,内容为空。
2. 字符比较:
- == 比较内存地址是否相等。
- equals
a. 先比较内存地址是否相等
b. 如果不相等,再去判断是否为String,然后再将每一个字符取出来判断相不相等。
String str1 = "AB"; String str2 = new String("AB"); if(str1.equals(str2)){ ... }
3. 常用方法(看文档):
// 获取长度 str.length(); // 获取字符串中某一字符 str.charAt(2); // 返回一个字符串在字符中第一次出现的位置 str.indexOf(str2); // 最后一次出现的位置(从左边开始数) str.lastIndexOf(str2); // 大写转小写 str1.toLowerCase(); // 小写转大写 str1.toUpperCase(); // 忽略大小写的比较 str1.equalsIgnoreCase(str2); // 字符串的分割 String[] res = str1.split(";"); // 去前后空格 str1.trim(); // 替换 str1.replace("a","b");
# day03
十八. 字符串(StringBuilder, StringBuffer)
- 可变字符串(效率高):
// StringBuilder : 没有(没有锁) synchronized StringBuilder i = new StringBuilder(); // StringBuffer : 有(加锁) synchronized StringBuffer i = new StringBuffer();
十九. Random 类
import java.uitl.Random; Random r = new Random(); // 生成随机的整数 () int res = r.nextInt(); // 生成 0 - 100 之间的整数 int res = r.nextInt(100); // 生成随机小数 r.nextDouble(); // 生成随机布尔值 r.nextBoolean(); // 相同的种子,生成的随机数是一样的(带参数)。 Random r2 = new Random(11); r2.nextInt();
二十. 生成 UUID
String uuid = UUID.randomUUID().toString();
二十一. 日期 Date 类
import java.util.Date; // 创建一个日期对象 Date date = new Date(); // 获取当前时间毫秒数 long curTime = System.CurrentTimeMillis(); // 把一个毫秒值转换日期类型 Date date = new Date(curTime); // 2019-4-3 11:15:00 日期格式 String str = date.toLocaleString(); // 日期格式化 // 19-4-3 上午11:46 格式 DateFormat df = DateFormat.getInstance(); // 长日期 LONG // 段日期 SHORT // 19-4-3 上午11:46 格式 DateFormat df2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); String time = df2.format(date); // 2019年4月3日 上午11时49分00秒 格式 DateFormat df2 = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); String time = df2.format(date); // 11:50:00 格式 DateFormat df = DateFormat.getTimeInstance(); String time = df.format(date); // 字符转日期 (需要添加异常声明 - main(String[] args) throws ParseException{ ... }) DateFormat df2 = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); String newStr = "2019年4月3日 上午11时49分00秒"; Date date = df2.parse(newStr); // 把一个日期转换毫秒值 date.getTime(); // 自定义日期格式 import java.util.Date; import java.text.SimpleDateFormat; Date date = new Date(); // 存放日期 SimpleDateFormat sd = new SimpleDateFormat(); // 自定义日期展示格式 String pattern = "yyyy-MM-dd HH/mm/ss"; sd.applyPattern(patern); // 以指定的模式格式化日期 String res = sd.format(date);
二十二. Collection
a. ArrayList 的使用:
import java.util.ArrayList; import java.util.Collection; 1. 添加元素 Collection c = new ArrayList(); c.add("abc"); // 自动装箱(把基本数据类型转成对象) 1.1 集合合并 c1.addAll(c2); 2. 删除指定元素 c.remove("abc"); 2.1 删除集合交集 c1.removeAll(c2); 3. 判断集合是否为空 c.isEmpty(); 3.1 判断调用的集合是否包含传入的集合(全部包含) boolean res = c1.containsAll(c2); 3.2 取交集 把交集的结果赋值给调用者(如果调用的集合改变,则返回true,否则返回false) boolean b = c1.retainAll(c2); System.out.println(c1); // 将两个集合一样的内容返回到调用集合中。 4. 获取集合长度 c.size(); 5. 清空集合 c.clear(); 6. 集合转普通数组 // 存放普通数据类型 Collection c = new ArrayList(); Object[] arr = c.toArray(); for(int i = 0; i < arr.length; i++){ System.out.println(arr[i]); } // 存放对象 Collection c2 = new ArrayList(); c2.add(new Dog("a")); c2.add(new Dog("b")); Object[] arr2 = c2.toArray(); // 自动把数组中所有元素向上转型(数组中都是Object) for(int i = 0; i < arr2.length; i++){ Dog d = (Dog)arr2[i]; // 向下转型 (子类(向下)/父类(向上)) System.out.println(d.getName()); } // Collection 迭代器遍历元素 Collection c = new ArrayList(); // 迭代器遍历(将集合中元素放到迭代器) Iterator it = c.iterator(); // 对象会提升为 Object // 获取迭代器中内容 it.next(); // 判断迭代器是否还有元素(返回 true or false) it.hasNext();
b. ArrayList 的 List 集合
- listIterator 在List 中特有的迭代器。
1. 创建
List list = new ArrayList(); ListIterator it = list.listIterator(); while(it.hasNext()){ list.add(); }
2. 迭代添加/删除元素并发异常
原因: 迭代器遍历时不能直接(list.add()) 添加/删除 list 中的元素,需要使用迭代器内置的 add/remove 删除。
- 内部有 modCount != expectedModCount; 每次循环进行判断,如果不相等就会抛异常。
- modCount : 集合修改次数(如 add() 一次就会记录一次)。
- expectedModCount : 迭代器中集合修改的次数。
解决:
- 每次 add/remove 会执行 modCount = expectedModCount
while(it.hasNext()){ it.add(); it.remove(); }
3. 判断当前元素是否存在与这个集合
newList.contains(obj);
c. LinkedList - 链式实现
- 添加/删除 速度快
- 查询 速度慢
import java.util.LinkedList; LinkedList list = new LinkedList(); // 将元素添加到集合 最前面和最后面 list.addFirst("add1"); list.addLast("add2"); // 将集合 最前面和最后面 的元素删除 list.removeFirst(); list.removeLast(); // 查询 list.get(0);
d. Vector (更多详细查文档)
- 和 ArrayList 差不多,只不过当前这个加锁了。
import java.util.Verctor; Vector vc = new Vector();
e. Set集合
1. HashSet / LinkedHashSet HashSet: - 无序,不重复。 import java.util.HashSet; import java.util.Iterator; HashSet<String> hs = new HashSet<String>(); hs.add("a"); Iteractor<String> it = hs.iterator(); while(it.hasNext()) { ... }
LinkedHashSet:
- 有序,不重复。
import java.util.LinkedHashSet; LinkedHashSet<String> set = new LinkedHashSet<>(); set.add("a");
f. TreeSet:
- 自动排序,不重复。
import java.util.TreeSet; TreeSet<Integer> set = new TreeSet<Integer>(); set.add(1);
- 比较器:
- 默认情况下, 比较时会调用对象的 compareTo 进行比较。
- 如果传入了 比较器,不会调用 compareTo, 就会使用传入的比较器。
import java.util.TreeSet; TreeSet<String> set = TreeSet<String>(); // 默认按字母的顺序,数字的大小...进行排序。 set.add("aa"); set.add("bb"); set.add("1"); // 使用比较器 // 实现一个接口 comparator。 // 定义一个类来实现这个接口。 // 覆盖里面的方法。 class CompareLength implements Comparator<String>{ // o1 : 当前正在添加的元素。 o2 : 集合当中的对象。 @override public int compare(String o1, String o2){ // 0 : 只添加第一个元素。 // 正数: 全部添加到集合中,按添加顺序。 // 负数: 全部添加到集合中,按添加顺序倒序。 return 0; } }
二十三. 泛型:
1. 定义:
- 泛型类:
- 在类上面定义的泛型,在创建对象的时候,指明泛型类型。
- 泛型中 定义的泛型只能用在普通方法上面。
- 静态方法(static)不能使用 (因为静态方法直接通过类名调用,而泛型必须实例的时候才指定类型)。
- 泛型方法:
- 对一个方法声明了泛型。
2. 注意:
- 泛型前后类型需保持一致。
- 可以这样写: Foo<String> foo = new Foo<>();
- 泛型欸有继承。
- 泛型其实时一个语法糖 (本质还是 Object, 内部做强转)
3. 使用:
// 泛型类
class Foo<T>{ ... } Foo<String> foo = new Foo<String>();
4. 自定义泛型方法
// 方法中定义的泛型,是在使用方法时,参数传递的数据类型。
<T> void test(T a){ System.out.println(a.getClass()); } new Student().test("a"); // 静态方法也可以使用泛型 static <E> void test(E name){ System.out.println(name.getClass()); } Student.test(true); static <E> E test1(E name){ return name } String str = Student.test1('f');
5. 泛型通配符:
- 一般用于接收
import java.util.List; import java.util.ArrayList; static void test(List<?> list){ ... } List<String> list = new ArrayList<>(); test(list);
// 泛型的上限和下限
// 上限: 用来指定元素的类型必须要是指定类型 (Number) 的子类,或者是指定类型。 static void test(List<? extends Number> list) { ... } // 下限: 用来指定元素的类型必须要是指定类型 (Number) 的父类,或者是指定类型。 static void test(List<? super Number> list) { ... }
// 泛型擦除
List<String> list = new ArrayList<>(); list.add("a") List list1 = null; list1 = list; // 把 list 当中的泛型给清除。 list1.add(19); list1.add("a");
二十四. List 与 数组之间的转换。
## 数组转集合
import java.util.Arrays; import java.util.List; // 1. 方式一 (不使用) int[] arr = {1,2,3}; // int - 基本数据类型 // 数组转集合 (转换后不能 添加/删除 元素) // 这种转法返回的只是一个内存地址 (将 arr 当成一个整体存储为一个对象) List list = Arrays.asList(arr); // 0xxx1 // 2. 方式二 (推荐使用) Integer[] arr = {1,2,3}; // 引用数据类型 List list = Array.asList(arr); // 返回的是一个集合 [1,2,3]
## 集合转数组
List<String> list = new ArrayList<>(); list.add("a"); list.add("a"); // 方法一: Object[] o = list.toArray(); // 方法二: String[] str = list.toArray(new String[]); // 可以写容量大小,容量不够会自动填充,超出用 null 表示。
二十五. 集合嵌套集合。
Person per1 = new Person("zs"); Person per2 = new Person("ls"); List<Person> c1 = new ArrayList<>(); c1.add(per1); c1.add(per2); Person per3 = new Person("w5"); Person per4 = new Person("xl"); List<Person> c2 = new ArrayList<>(); c1.add(per3); c1.add(per4); // 集合类型是 List<Person> 嵌套 List<List<Person>> x = new ArrayList(); x.add(c1); x.add(c2);
二十六. Map
HashMap:
- key 无序
// 创建 Map<String,Object> map = new HashMap<String,Object>(); 1. 获取所有 keys Set<String> keys = map.keySet(); 2. 获取所有 values Collection<Object> values = map.values(); 3. 添加元素 map.put("k1":"k2"); 4. 修改元素 // 如果keys存在,那么会将 Values 覆盖,并返回原本 values。 map.put("k1":"k2"); 5. 删除元素 map.remove("k1"); 6. 清空字典 map.clear(); 7. 获取字典元素个数 map.size(); 8. 获取一个 keys 的 values map.get("k1");
9. 遍历元素
// 通过 iterator 遍历。 Set<String> allKeys = map.keySet(); Iterator<String> it = allKeys.iterator(); while(it.hasNext()){ String key = it.next(); Object values = map.get(key); System.out.println(key+":"+values); } // 使用 foreach 遍历。 for(String key : map.keySet()){ System.out.println(key+":"+map.get(key)); } // 使用 entry 遍历。 // 创建 一个字典。 Map<String, Integer> map = new HashMap(); map.put("K1":"v1"); ... // 获取所有的 entry 对象。 Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); // 遍历每一个entry对象。 Iterator<Entry<String, Integer>> it = entrySet.iterator(); while(it.hasNext()){ // 取出每一个 key:value Entry<String, Integer> en = it.next(); // 获取 key String key = en.getKey(); // 获取 value Integer value = en.getValue(); } // foreach 写法 for(Entry<String, Integer> entry:entrySet){ System.out.println(entry.getKey() + ":" + entry.getValue()); }
10. LinkedHashMap / TreeMap
LinkedHashMap:
- key 的排序顺序为添加顺序
LinkedHashMap<String, Integer> hm = new LikedHashMap<>();
TreeMap:
- 会对 key 进行排序(其余实现和 TreeSet一致)
TreeMap<String, Integer> treeMap = new TreeMap<>();
二十七. 异常
1. 捕获异常:
try{ }catch(Exception e){ //1. 获取异常信息,参数 e.getMessage(); //2. 获取异常类名和异常信息 e.toString(); //3. 获取异常 类名,错误信息 和出错位置 e.printStackTrace(); }
2. 抛出异常:
// 2.1 抛出运行异常 throw new RuntimeException("异常信息"); // 2.2 抛出编译异常 // 必须要处理 throw new Exception("异常信息"); // 处理方式 : //1. try // 2. throws Exception 继续向上抛(将异常给类 throws 可以跟多个异常) public void Foo() throws Exception, RuntimeException{ ... }
2.3 finally
try{ }catch(Exception e){ }finally{ // 不管有没有异常,这里都会执行。 }
3. 自定义异常:
3.1 运行异常
- 定义一个类继承 Exception。
- 抛出异常时,只需要抛出定义的类名。
class MyException extends RuntimeException{ // 自定义异常参数 MyException(String message){ super(message); } } throw new MyException("异常信息");
3.2 编译异常
class MyException extends Exception{ } // 或者继续向上抛异常 (类) try{ ... }catch(MyException e){ ... }