⭐java泛型
- Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
集合中使用泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Test void t4() { ArrayList<Integer> list = new ArrayList<>(); list.add(78); list.add(88); list.add(77); list.add(66); for (Integer i : list) { System.out.println(i); } Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } Map<String, Integer> map = new HashMap<String, Integer>(); map.put("Tom1", 34); map.put("Tom2", 44); map.put("Tom3", 33); map.put("Tom4", 32); Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); Iterator<Map.Entry<String, Integer>> iterator = entrySet.iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); System.out.println(entry.getKey() + "--->" + entry.getValue()); } }
|
自定义泛型
泛型类
泛型的声明
interface List 和 class GenTest<K,V> 其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。
T只能是类,不能用基本数据类型填充。但可以使用包装类填充
把一个集合中的内容限制为一个特定的数据类型,这就是generics背后的核心思想
-
泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
-
泛型类的构造器如下:public GenericClass(){}。
- 而下面是错误的:public GenericClass(){}
-
实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
-
泛型不同的引用不能相互赋值。
-
尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中。
-
泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:==泛型要使用一路都用。要不用,一路都不要用。==
-
如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
-
jdk1.7,泛型的简化操作:ArrayList flist = new ArrayList<>();
-
==泛型的指定中不能使用基本数据类型==,可以使用包装类替换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class GenericTest { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("hello"); test(list); } public static void test(ArrayList<String> list) { String str = ""; for (String s : list) { str += s + ","; } System.out.println("元素:" + str); } }
|
-
在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。
-
==异常类不能是泛型的==
-
不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity];参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。
-
父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
-
子类不保留父类的泛型:按需实现
1.没有类型 擦除
2.具体类型
-
子类保留父类的泛型:泛型子类
1.全部保留
2.部分保留
结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Father<T1, T2> { }
class Son1 extends Father { }
class Son2 extends Father<Integer, String> { }
class Son3<T1, T2> extends Father<T1, T2> { }
class Son4<T2> extends Father<Integer, T2> { } 12.3 自定义泛型结构:泛型类、泛型接口 class Father<T1, T2> { }
class Son<A, B> extends Father{ }
class Son2<A, B> extends Father<Integer, String> { }
class Son3<T1, T2, A, B> extends Father<T1, T2> { }
class Son4<T2, A, B> extends Father<Integer, T2> { }
|
泛型方法
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型
方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法的格式:
[访问权限]<泛型> 返回类型 方法名([泛型标识 参数名称])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public <E> List<E> copyFromArrayToList(E[] arr) { ArrayList<E> list = new ArrayList<E>(); for (E temp : arr) list.add(temp); return list;
} @Test void t2() { Integer[] arr = new Integer[]{12, 54, 76, 8, 978}; Order<String> order = new Order<>(); List<Integer> list = order.copyFromArrayToList(arr); }
|
泛型在继承上的体现
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G并不是G的子类型
注意:A B可以转换
1 2 3
| List<String> list1=null; ArrayList<String> list2=null; list1=list2;
|
1 2 3 4 5 6 7 8 9
| @Test void t1() { Object obj = null; String str = null; obj = str; List<Object> list1 = null; List<String> list2 = null;
}
|
通配符的使用
1 2 3 4 5 6 7 8 9
| @Test void t2() { List<String> list1 = null; ArrayList<String> list2 = null; list1 = list2; List<?> list = null; list = list1; list = list2; }
|
类A是类B的父类,G与G没有关系,二者共同的父类是G<?>;
1.使用通配符后的读取和写入要求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Test void t2() { List<String> list1 = null; ArrayList<String> list2 = null; list1 = list2; List<?> list = null; list = list1; list = list2; List<String> list3 = new ArrayList<>(); list3.add("AAA"); list3.add("BBB"); list3.add("CCC");
list = list3; System.out.println(list.get(1)); print(list); }
|
无法向List<?>中添加元素,可以get(int idx),返回值是Object类型
2.有限制条件的通配符的使用
1 2 3 4 5 6 7 8 9 10 11 12
| @Test void t3() { List<? extends Person> list1 = null; List<? super Person> list2 = null; List<Person> list3 = null; List<Object> list4 = null; list1 = list3; list2 = list3; list2 = list4; }
|
- 注意加了限制条件的 List<?>仍然无法add()
1 2 3 4 5 6 7
| public static void main(String[] args) { List<? extends Object> list = null; List<String> list1 = null; list1.add("4234"); list = list1; }
|
🌟java IO流
File类的使用
- File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
- java.io package下
i: input
o:output
1.File类的实例化
==注意==:如果File 对象初始化的文件不存在,那么此时的File对象仅仅只是内存中的一个对象,不会创建文件。
常用构造器
public File(String pathname)
public File(String parent,String child)
- 以parent为父路径,child为子路径创建File对象。
public File(File parent,String child)
- 根据一个父File对象和子文件路径创建File对象
路径分隔符
1.路径中的每级目录之间用一个路径分隔符隔开。
2.路径分隔符和系统有关:
-
windows和DOS系统默认使用“\”来表示
-
UNIX和URL使用“/”来表示
3.java程序支持跨平台运行,因此路径分隔符要慎用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test void t1() { File file1 = new File("C:/Users/lenovo/Desktop/javaIO.txt"); File file2 = new File("javaIO.txt"); System.out.println(file1); System.out.println(file2.getClass()); File file3 = new File("C:/Users/lenovo/Desktop", "Cpp"); System.out.println(file3); File file4 = new File(file3, "javaIO file4.txt"); System.out.println(file4); }
|
2.常用方法
1️⃣File类的获取功能
- public String getAbsolutePath():获取绝对路径
- public String getPath() :获取路径
- public String getName() :获取名称
- public String getParent():获取上层文件目录路径。若无,返回null
- public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
- public long lastModified() :获取最后一次的修改时间,毫秒值
- public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
- public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Test void t2() { SimpleDateFormat sdf = new SimpleDateFormat(); File file1 = new File("helloJavaIO.txt"); File file2 = new File("C:/Users/lenovo/Desktop/helloJavaIO.txt"); System.out.println("绝对路径 " + file1.getAbsolutePath()); System.out.println("相对路径 " + file1.getPath()); System.out.println("文件名 " + file1.getName()); System.out.println("获取上级目录 " + file1.getParent()); System.out.println("长度" + file1.length()); System.out.println("最后一次的修改时间(已经使用SimpleDateFormat格式化) :" + sdf.format(file1.lastModified())); System.out.println(); System.out.println(file2.getAbsolutePath()); System.out.println(file2.getPath()); System.out.println(file2.getName()); System.out.println(file2.getParent()); System.out.println(file2.length()); System.out.println(file2.lastModified()); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test void t3() { File file = new File("C:/Users/lenovo/Desktop/java/SUMMER_JAVA"); String[] list = file.list(); for (String s : list) { System.out.println(s); } File[] files = file.listFiles(); System.out.println(); try { for (File f : files) { System.out.println(f); } } catch (Exception e) { e.printStackTrace(); } }
|
2️⃣File类的重命名功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径13.1 File 类的使用:常用方法
1 2 3 4 5 6 7 8 9 10
| @Test void t4() {
File file1 = new File("helloJavaIO.txt"); File file2 = new File("C:/Users/lenovo/Desktop/IOTest.txt"); boolean renameTo = file1.renameTo(file2);
System.out.println(renameTo); }
|
3️⃣File类的判断功能
- public boolean isDirectory():判断是否是文件目录
- public boolean isFile() :判断是否是文件
- public boolean exists() :判断是否存在
- public boolean canRead() :判断是否可读
- public boolean canWrite() :判断是否可写
- public boolean isHidden() :判断是否隐藏
1 2 3 4 5 6 7 8
| void t5() { File file = new File("helloJavaIO.txt"); System.out.println(file.isFile()); System.out.println(file.isDirectory()); System.out.println(file.exists()); System.out.println(file.canRead()); System.out.println(file.isHidden()); }
|
4️⃣File类的创建功能
-
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
-
public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
-
public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建
注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目路径下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Test void t6() { File file = new File("C:/Users/lenovo/Desktop/Test.doc"); if (!file.exists()) { try { file.createNewFile(); System.out.println("创建成功! "); } catch (IOException e) { e.printStackTrace(); } } else { if (file.delete()) System.out.println("delete successfully!"); } File file1 = new File("C:/Users/lenovo/Desktop/Test"); if (!file1.exists()) if (file1.mkdir()) System.out.println("mkdir()创建成功!"); File file2 = new File("C:/Users/lenovo/Desktop/TEstIO/hello"); if (!file2.exists()) if (file2.mkdirs()) System.out.println("mkdirs()创建成功!"); if (file.exists()) file.delete(); }
|
5️⃣File类的删除功能
练习:判断指定目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static void main(String[] args) { t(new File("E:\\vscode_background")); }
static void t(File file) { File[] files = file.listFiles(); for (File file1 : files) { String str = new String(file1.getName()); str = new String(str.substring(str.length() - 3, str.length())); if (str.equals("jpg")) { System.out.println(file1.getName()); } } }
static void f(File file) { String[] name = file.list(); for (String s : name) { if (s.substring(s.length() - 3).equals("jpg")) { System.out.println(s); } } }
|