泛型
一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
好处
将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
避免了类型强转的麻烦
泛型是数据类型的一部分,通常将类名与泛型合并一起看做数据类型
public class genericDemo01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
ArrayList list1 = new ArrayList();
list1.add("abc");
list1.add(true);
list1.add('c');
list1.add(123);
for (Object o : list1) {
System.out.println(o);
}
//Exception in thread "main" java.lang.ClassCastException: class java.lang.Boolean cannot be cast to class java.lang.String
/* for (Object o : list1) {
String str = (String) o;
System.out.println(str.length());
}*/
}
}
定义与使用
通常在集合中泛型比较常用。
但是泛型也可以用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递。
定义和使用含有泛型的类
比如说ArrayList集合中的使用
也可以自定义泛型,比如以下代码
public class Generic {
/**
* 泛型修饰方法
* 修饰符<字母> 返回值类型 方法名称(字母 变量名){}
*/
/**
* 无返回值
* @param t 参数
* @param <T> 数据类型
*/
public static <T> void method(T t){
System.out.println(t);
}
/**
* 返回值为泛型
* @param t 参数
* @param <T> 数据类型
* @return 泛型参数
*/
public static <T> T method1(T t){
return t;
}
}
泛型的使用
public class GenericTest {
public static void main(String[] args) {
//自定义泛型
//定义的是静态方法,直接通过类名.方法调用
//调用无返回值方法
Generic.method("abc");
Generic.method('a');
Generic.method(true);
Generic.method(12.3);
Generic.method(new String("张三"));
System.out.println("===========");
String s = Generic.method1("1234");
System.out.println(s);
Integer intNumber = Generic.method1(123);
System.out.println(intNumber);
}
}
泛型接口
public interface GenericInterface <A>{
public void method(A a);
}
接口实现
public class GenericInterfaceImpl implements GenericInterface<String> {
@Override
public void method(String s) {
}
}
public class GenericInterfaceImpl02<A> implements GenericInterface<A> {
@Override
public void method(A a) {
}
}
接口的测试
public class GenericTest {
public static void main(String[] args) {
/**
* MyInterface接口的实现类
* 之前实现接口,在实现类中直接重写抽象方法即可
* 现在实现的接口,该接口上有泛型的
*
* 两种格式:
* 1. 实现该接口时,能确定接口泛型的数据类型是什么了
* 2. 实现该接口时,不能确定接口泛型的数据类型是什么,该实现类上要写泛型
*/
GenericInterfaceImpl genericInterface = new GenericInterfaceImpl();
genericInterface.method("ssss");
GenericInterfaceImpl02<String> stringGenericInterfaceImpl02 = new GenericInterfaceImpl02<>();
stringGenericInterfaceImpl02.method("字符串");
}
}
泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
通配符的高级使用--受限泛型
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限和下限
泛型的上限 `
类型名称 <? extends 类 > 对象名称
` 只能接收该类型及该类型的子类泛型的下限 `
类型名称 <? super 类 > 对象名称
` 只能接受该类型及该类型的父类型
比如以下代码:
public class GenericCase {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement1(list1);
// getElement1(list2);
getElement1(list3);
// getElement1(list4);
// getElement2(list1);
// getElement2(list2);
getElement2(list3);
getElement2(list4);
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
}
测试类
public class GenericTest {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("abc");
list1.add("bce");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(123);
list2.add(456);
//遍历集合
for (String s : list1) {
System.out.println(s);
}
System.out.println("============");
for (Integer integer : list2) {
System.out.println(integer);
}
System.out.println("=============");
//两个集合遍历太过于麻烦。使用泛型来遍历
printList(list1);
printList(list2);
}
/*
不管你的集合中存储的是什么元素类型,我只做遍历,不关心集合中元素的类型
可以使用一个通配符,进行完成遍历的功能
? --> <?>
? 通配符的好处:
可以遍历集合中元素的类型是任意类型的数据
缺点:
只能做遍历或者删除元素,不能做其它操作
*/
public static void printList(ArrayList<?>list){
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
File类
java.io.File
类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。
File类的构造方法
方法名 | 说明 |
---|---|
public File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 |
public File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的 File实例。 |
public File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的 File实例。 |
public class FileDemo02 {
public static void main(String[] args) {
/**
* File(String pathname) :将一个字符串路径封装成File对象
* File(String parent,String child) :传入一个父级路径和子级路径
* File(File parent,String child) :传入一个File类型的父级路径和子级路径
*/
File file = new File("C:\\Users\\Administrator\\Desktop\\资料\\day10泛型\\代码\\day10_file\\src\\com\\itfxp\\file\\FileDemo.java");
System.out.println(file);
File file1 = new File("C:\\Users\\Administrator\\Desktop\\资料\\day10泛型\\代码\\day10_file\\src\\com\\itfxp\\file", "FileDemo02.java");
System.out.println(file1);
/**
* // 复制文件夹时,会用到路径的拼接
* // 做路径拼接时,经常会用到File类中的静态常量:separator : \ /
* // 这个地方动态的获取当前系统的文件或目录的路径的分隔符
* // Z:+File.separator + upload + File.separator + 1.jpg
* // File(File parent,String child) :传入一个File类型的父级路径和子级路径
*/
File file2 = new File("C:\\Users\\Administrator\\Desktop\\资料\\day10泛型\\代码\\day10_file\\src\\com\\itfxp\\file");
new File(file2,"FileDemo02.java");
}
}
注意事项:
一个File对象代表硬盘中实际存在的一个文件或者目录
无论该路径下是否存在文件或者目录,都不会影响File对象的创建
File获取功能方法
方法名 | 说明 |
---|---|
public String getAbsolutePath() | 返回此File的绝对路径名字符串。 |
public String getPath() | 将此File转换为路径名字符串 |
public String getName() | 返回由此File表示的文件或目录的名称。 |
public long length() | 返回由此File表示的文件的长度。 |
public class FileGetMethod {
public static void main(String[] args) {
/**
* public String getAbsolutePath()返回此File的绝对路径名字符串。
* public String getPath()将此File转换为路径名字符串
* public String getName()返回由此File表示的文件或目录的名称。
* public long length()返回由此File表示的文件的长度。
* String getParent() :返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
* File getParentFile() :返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。
*/
File file = new File("D:\\jdk\\conf\\sound.properties");
//public String getAbsolutePath()返回此File的绝对路径名字符串。
String absolutePath = file.getAbsolutePath();
System.out.println(absolutePath);
//public String getPath()将此File转换为路径名字符串
String path = file.getPath();
System.out.println(path);
//public String getName()返回由此File表示的文件或目录的名称。
String name = file.getName();
System.out.println(name);
//public long length()返回由此File表示的文件的长度。
long length = file.length();
System.out.println(length);
//String getParent() :返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
String parent = file.getParent();
System.out.println(parent);
//File getParentFile() :返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。
File parentFile = file.getParentFile();
System.out.println(parentFile);
}
}
File的绝对路径和相对路径
绝对路径:从盘符开始的路径,是一个完整的路径
相对路径:相对于项目目录的路径,是一个便捷的路径,开发中经常用相对路径
public class PathTest {
public static void main(String[] args) {
/**
* 绝对路径:从盘符开始的路径
* 相对路径:相对于项目目录的路径,是一个便捷的路径,开发中经常使用
*/
//盘符下的路径
File file = new File("d:\\qq\\a.txt");
System.out.println(file.getAbsoluteFile());
//项目中的路径
File file1 = new File("day120427\\code\\file\\path.txt");
System.out.println(file1.getAbsoluteFile());
}
}
File的判断功能的方法
方法名 | 说明 |
---|---|
public boolean exists() | 此File表示的文件或目录是否实际存在。 |
public boolean isDirectory() | 此File表示的是否为目录。 |
public String getName() | 返回由此File表示的文件或目录的名称。 |
public class JudgeTest {
public static void main(String[] args) {
/**
* public boolean exists()此File表示的文件或目录是否实际存在。
* public boolean isDirectory()此File表示的是否为目录。
* public String getName()返回由此File表示的文件或目录的名称。
* boolean isHidden() : 判断当前路径是否是隐藏文件
*/
//public boolean exists()此File表示的文件或目录是否实际存在。
File file = new File("D:\\jdk\\conf\\logging.properties");
boolean flag = file.exists();
System.out.println(flag);//true
//不存在的文件
File file1 = new File("D:\\test.txt");
boolean exists = file1.exists();
System.out.println(exists);//false
//public boolean isDirectory()此File表示的是否为目录。
boolean isFlag = file.isDirectory();
System.out.println(isFlag);//不是目录。是一个文件
File file2 = new File("D:");
boolean directory = file2.isDirectory();
System.out.println(directory);//D盘是一个目录
//public String getName()返回由此File表示的文件或目录的名称。
String name = file.getName();//logging.properties
System.out.println(name);
String name1 = file2.getName();
System.out.println(name1);//无字天书,不显示D:
//boolean isHidden() : 判断当前路径是否是隐藏文件
boolean hidden = file.isHidden();
System.out.println(hidden);//false
}
}
File创建删除功能的方法
方法名 | 说明 |
---|---|
public boolean createNewFile() | 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。 |
public boolean delete() | 删除由此File表示的文件或目录。 |
public boolean mkdir() | 创建由此File表示的目录。 |
public boolean mkdirs() | 创建由此File表示的目录,包括任何必需但不存在的父目录。 |
public class EstablishDeleteTest {
public static void main(String[] args) throws IOException {
/**
* public boolean createNewFile()当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
* public boolean delete()删除由此File表示的文件或目录。
* public boolean mkdir()创建由此File表示的目录。
* public boolean mkdirs()创建由此File表示的目录,包括任何必需但不存在的父目录。
*/
//public boolean createNewFile()当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
//创建文件
File file = new File("java.text");
System.out.println(file.exists());//是否存在 false
System.out.println(file.createNewFile()); //创建
System.out.println(file.exists());//是否存在 true
//创建目录
File jdbc = new File("jdbc");
System.out.println(jdbc.exists());//是否存在 false
System.out.println(jdbc.mkdir());//创建目录 创建
System.out.println(jdbc.exists());//是否存在 true
//创建多级目录
File file1 = new File("newDir\\newTest");
System.out.println(file1.mkdir());//false
File file2 = new File("newDir\\newTest");
System.out.println(file2.mkdirs());//true
//public boolean delete()删除由此File表示的文件或目录。
System.out.println(file.delete());//true
System.out.println(jdbc.delete());//true
System.out.println(file1.delete());//true
System.out.println(file2.delete());
}
}
File目录的遍历
方法名 | 说明 |
---|---|
public String[] list() | 返回一个String数组,表示该File目录中的所有子文件或目录。 |
public File[] listFiles() | 返回一个File数组,表示该File目录中的所有的子文件或目录。 |
public class FileFor {
public static void main(String[] args) {
/**
* public String[] list()返回一个String数组,表示该File目录中的所有子文件或目录。
* public File[] listFiles()返回一个File数组,表示该File目录中的所有的子文件或目录。
* static File[] listRoots() :获取计算机中所有的盘符
*/
//public String[] list()返回一个String数组,表示该File目录中的所有子文件或目录。
File file = new File("D:\\jdk\\conf");
String[] list = file.list();
for (String s : list) {
System.out.println(s);
}
//public File[] listFiles()返回一个File数组,表示该File目录中的所有的子文件或目录。
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println(file1);
}
//调用listFiles方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历。
//static File[] listRoots() :获取计算机中所有的盘符
File[] files1 = File.listRoots();
for (File file1 : files1) {
System.out.println(file1);
}
}
}
注意:调用listFiles方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历
递归
递归是指在当前方法内调用自己;分为直接递归和间接递归
注意事项:递归一定有条件限定,保证递归能停止下来,否则会发生栈内存溢出
在递归中虽然有条件限定,但是递归次数不能太多,否则也会发生栈内存溢出
构造方法禁止递归。
递归的小练习
public class Recursion {
public static void main(String[] args) {
/**
* 使用递归求5的阶乘
*/
int sum = getSum(5);
System.out.println(sum);
}
public static int getSum(int num){
if (num == 1){
return 1;
}
return num*getSum(num-1);
}
}
递归打印多级目录
public class RecursionTest01 {
public static void main(String[] args) {
/**
* 递归打印多级目录
* 案例演示: 找出一个文件夹下所有的文件和文件夹(包含子目录)
*
* 假设给的一个目录的路径day10_file目录路径
*/
//创建File对象
File file = new File("day140427");
printFileName(file);
}
public static void printFileName(File file){
//获取该目录下所有的文件及目录
File[] files = file.listFiles();
//遍历文件数组
for (File file1 : files) {
//如果该file1是一个文件直接输出
if (file1.isFile()){
System.out.println(file1);
//如果该file1是一个目录递归调用printFileName方法
}else if (file1.isDirectory()){
printFileName(file1);
}
}
}
}
File与递归综合练习
public class RecursionTest02 {
public static void main(String[] args) {
/**
* 综合案例之多级目录搜索
* 案例演示: 找出一个文件夹下所有的.java文件(包含子目录)
*/
File file = new File("day140427");
printFileName(file);
}
public static void printFileName(File file){
File[] files = file.listFiles();
for (File file1 : files) {
//如果file1是一个文件
if (file1.isFile()){
//如果file1.getName是以.java结尾的,则输出
if (file1.getName().endsWith(".java")){
System.out.println(file1);
}
}else {
printFileName(file1);
}
}
}
}