一:Java 概述
一、简介
1. 定义:Java 是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。应用在桌面应用程序、Web应用程序、分布式系统和嵌入式系统等领域。
2. 发展历程
1. 1996年1月,Sun公司发布了Java的第一个开发工具包(JDK 1.0),这是Java发展历程中的重要里程碑,标志着Java成为一种独立的开发工具。
2. 1999年6月,Sun公司发布了第二代Java平台(简称为Java2)的3个版本:J2ME(Java2 Micro Edition,Java2平台的微型版),应用于移动、无线及有限资源的环境;J2SE(Java 2 Standard Edition,Java 2平台的标准版),应用于桌面环境;J2EE(Java 2Enterprise Edition,Java 2平台的企业版),应用于基于Java的应用服务器。Java 2平台的发布,是Java发展过程中最重要的一个里程碑,标志着Java的应用开始普及。
3. 2005年6月,在Java One大会上,Sun公司发布了Java SE 6。此时,Java的各种版本已经更名,已取消其中的数字2,如J2EE更名为JavaEE,J2SE更名为JavaSE,J2ME更名为JavaME。
4. 2007年3月起,全世界所有的开发人员均可对Java源代码进行修改。
5. 2009年,甲骨文公司宣布收购Sun。2014年,甲骨文公司发布了Java8正式版
二、编程开发
1. 开发环境
1. JDK(Java Development Kit)称为Java开发包或Java开发工具,是一个编写Java的Applet小程序和应用程序的程序开发环境。JDK是整个Java的核心,包括了Java运行环境(Java Runtime Environment),一些Java工具和Java的核心类库(Java API)。不论什么Java应用服务器实质都是内置了某个版本的JDK。主流的JDK是Sun公司发布的JDK,除了Sun之外,还有很多公司和组织都开发了自己的JDK,例如,IBM公司开发的JDK,BEA公司的Jrocket,还有GNU组织开发的JDK [13] 。
2. JRE(JAVA Runtime Environment)是JavaSE API子集和Java虚拟机这两部分的统称,是支持Java程序运行标准环境。JDK默认集成JRE,但是运行普通Java程序只需安装JRE。
2. 开发工具
1. Eclipse:一个开放源代码的、基于Java的可扩展开发平台。
2. NetBeans:开放源码的Java集成开发环境,适用于各种客户机和Web应用。
3. IntelliJ IDEA:在代码自动提示、代码分析等方面的具有很好的功能。
4. MyEclipse:由Genuitec公司开发的一款商业化软件,是应用比较广泛的Java应用程序集成开发环境
三、特点
1. 简单性:Java 摒弃了C++的操作符过载、多继承特征、结构和指针,能够自动处理对象的引用和间接引用。
2. 面向对象:Java 是一个面向对象的语言。类(class)是数据和操作数据的方法的集合,数据(data)和方法(method)一起描述对象(object)的状态和行为。除此之外Java还可以使用各种程序包(Package)。
3. 分布性:Java 程序编译一次即可到处运行。Java既支持各种层次的网络连接,又以Socket类支持可靠的流(stream)网络连接,所以用户可以产生分布式的客户机和服务器。
4. 编译和解释性:Java 编译程序最终生成字节码(byte-code)文件,而不是通常的机器码,可以在任何实现了Java解释程序和运行系统(run-time system)的系统上运行。
5. 稳健性:Java是一个强类型语言,它允许扩展编译时检查潜在类型不匹配问题的功能。Java要求显式的方法声明,它不支持C风格的隐式声明。这些严格的要求保证编译程序能捕捉调用错误,这就导致更可靠的程序。
6. 安全性:Java的存储分配模型是它防御恶意代码的主要方法之一。Java没有指针,所以程序员不能得到隐蔽起来的内幕和伪造指针去指向存储器。更重要的是,Java编译程序不处理存储安排决策,所以程序员不能通过查看声明去猜测类的实际存储安排。编译的Java代码中的存储引用在运行时由Java解释程序决定实际存储地址。Java运行系统使用字节码验证过程来保证装载到网络上的代码不违背任何Java语言限制。
7. 可移植性:Java 使得语言声明不依赖于实现的方面,Java 环境本身对新的硬件平台和操作系统是可移植的。
8. 高性能:Java 字节码格式设计时考虑到这些“及时”编译程序的需要,所以生成机器代码的过程相当简单,它能产生相当好的代码。
9. 多线程:Java 是多线程语言,它提供支持多线程的执行(也称为轻便过程),能处理不同任务,使具有线索的程序设计很容易。Java的lang包提供一个Thread类,它支持开始线索、运行线索、停止线索和检查线索状态的方法。
10. 动态性:Java 语言设计成适应于变化的环境,它是一个动态的语言。例如,Java中的类是根据需要载入的,甚至有些是通过网络获取的。
四、学习路线
二:Java 基础知识
一、标识符和关键字
1. 标识符
1. 在java语言中,用来标志类名、对象名、变量名、方法名、类型名、数组名、包名的有效字符序列,称为“标识符”;
2. 标识符由字母、数字、下划线、美元符号组成,且第一个字符不能是数字;
3. java语言区分大小写;
4. 标志符命名规则:类名首字母大写,变量名和方法名采用驼峰标志法,包名全小写,常量全大写,多个单词之间用“_”隔开;
2. 关键字
1. 在java语言中,有一些专门的词汇已经被赋予了特殊的含义,不能再使用这些词汇来命名标识符,这些专有词汇,称为“关键字”;
2. java有50个关键字和3个保留字,均不能用来命名标识符;
3. true、false、null不是关键字,是保留字,但是仍不能用来命名标识符;
二、数据类型
1. 分类
2. 存储原理
1. 基本类型的存储原理:直接存储在内存中的内存栈上的,数据本身的值就是存储在栈空间里面,而Java语言里面八种数据类型是这种存储模型;
2. 引用类型的存储原理:按照存储对象的内存模型来进行数据存储的,“引用”是存储在有序的内存栈上的,而对象本身的值存储在内存堆上的;
三、运算符
四、流程控制语句
1. 条件分支语句
1 package pers.mj; 2 3 import org.junit.Test; 4 5 public class Demo { 6 @Test 7 public void test() { 8 int a = 10; 9 int b = 5; 10 11 // if 条件判断 12 if (a > 8) { // 条件 13 System.out.println(a + "大于8"); 14 if (a < 12) { 15 System.out.println(a + "小于12"); 16 } 17 } else { 18 System.out.println(a + "小于8"); 19 } 20 21 // switch 条件判断 22 // switch 语句中的变量类型可以是: byte、short、int 或者 char。 23 // 从 Java SE 7 开始,switch支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。 24 char job = 'C'; 25 switch (job) { 26 case 'A': 27 System.out.println("优秀"); 28 break; 29 case 'B': 30 System.out.println("良好"); 31 break; 32 case 'C': 33 System.out.println("及格"); 34 break; 35 default: 36 System.out.println("不及格"); 37 break; 38 } 39 } 40 }
2. 循环语句
1 package pers.mj; 2 3 import static org.hamcrest.CoreMatchers.instanceOf; 4 5 import org.junit.Test; 6 7 public class Demo { 8 @Test 9 public void test() { 10 int sum = 0; 11 int i = 0; 12 // while 循环:迭代条件明确的数据 13 while (i <= 100) { 14 sum+=i; 15 i++; 16 } 17 System.out.println(sum); 18 19 // for 循环:迭代条件明确的数据 20 for (int j = 0; j <= 100; j++) { 21 sum += j; 22 } 23 System.out.println(sum); 24 25 // foreach 循环:用来迭代引用类型数据 26 int [] array = {0,1,2,3,4,5,6}; 27 for (int j : array) { 28 System.err.println(j); 29 } 30 } 31 }
三:数组
一、概述
1. 数组的概念:相同数据类型元素的集合
2. 数组的作用:用来存储基本数据类型和引用数据类型的数据
二、常用操作
1 public class TestArray { 2 public static void main(String[] args) { 3 /** 4 * 1. 数组的初始化 5 */ 6 // 1.1 数组的静态初始化 7 int[] array1 = { 1, 3, 5, 6, 7, 2, 4, 10 }; 8 9 // 1.2 数组的动态初始化 10 int[] array2 = new int[5]; 11 array2[0] = 1; 12 array2[1] = 2; 13 array2[2] = 7; 14 array2[3] = 3; 15 array2[4] = 4; 16 17 /** 18 * 2. 数组的遍历 19 */ 20 // 2.1 for循环打印数组 21 for (int i = 0; i < array2.length; i++) { 22 System.out.print(array2[i]); 23 } 24 25 // 2.2 foreach打印数组 26 for (int i : array2) { 27 System.out.print(i); 28 } 29 30 /** 31 * 3. 数组排序 32 */ 33 34 // 3.1 冒泡排序 35 for (int i = 0; i < array2.length; i++) { 36 for (int j = i + 1; j < array2.length; j++) { 37 // 1. 比较相邻元素,将较大的数冒泡 38 if (array2[i] > array2[j]) { 39 // 2. 交换 40 int temp = array2[i]; 41 array2[i] = array2[j]; 42 array2[j] = temp; 43 } 44 } 45 } 46 for (int i : array2) { 47 System.out.println(i); 48 } 49 50 // 3.2 选择排序 51 for (int i = 0; i < array2.length; i++) { 52 int min = i; 53 for (int j = i; j < array2.length; j++) { 54 // 1. 找到最小的数 55 if (array2[j] < array2[min]) { 56 // 2. 将最小的数赋值给min 57 min = j; 58 } 59 } 60 // 3. 交换两个数的位置 61 int temp = array2[i]; 62 array2[i] = array2[min]; 63 array2[min] = temp; 64 } 65 for (int i : array2) { 66 System.out.println(i); 67 } 68 69 // 3.3 反转排序 70 for (int i = 0; i < array2.length / 2; i++) { 71 // 将第i位元素与array2.length-1-i位元素交换 72 int temp = array2[i]; 73 array2[i] = array2[array2.length - 1 - i]; 74 array2[array2.length - 1 - i] = temp; 75 } 76 for (int i : array2) { 77 System.out.println(i); 78 } 79 80 // 3.4 插入排序 81 for (int i = 0; i < array2.length; i++) { 82 int j = i; 83 int tmp = array2[i]; 84 for (; j > 0 && tmp < array2[j - 1]; j--) { 85 // 1. 将大于待排序的数向后移 86 array2[j] = array2[j - 1]; 87 } 88 // 2. 交换 89 array2[j] = tmp; 90 } 91 for (int i : array2) { 92 System.out.println(i); 93 } 94 } 95 }
三、Arrays工具类
1 package pers.mj; 2 3 import static org.hamcrest.CoreMatchers.instanceOf; 4 5 import java.util.Arrays; 6 import java.util.List; 7 8 import org.junit.Test; 9 10 public class Demo { 11 @Test 12 public void test() { 13 14 int[] array1 = { 1, 3, 5, 2, 4 }; 15 int[] array2 = { 3, 2 }; 16 17 // 1. 排序 18 Arrays.sort(array2); 19 for (int i : array2) { 20 System.out.print(i); 21 } 22 23 // 2. 二分法查找 24 System.out.print(Arrays.binarySearch(array2, 3)); 25 26 // 3. 数组元素比较 27 System.out.println(Arrays.equals(array1, array2)); 28 29 // 4. 数组元素填充 30 Arrays.fill(array2, 1); 31 for (int j : array2) { 32 System.out.println(j); 33 } 34 35 /** 36 * aslist详解 37 * 1. 该方法适用于对象型数据的数组(String、Integer...) 38 * 2. 该方法不建议使用于基本数据类型的数组(byte,short,int,long,float,double,boolean) 39 * 3. 该方法将数组与List列表链接起来:当更新其一个时,另一个自动更新 40 * 4. 不支持add()、remove()、clear()等方法 41 */ 42 43 // 1、对象类型(String型)的数组数组使用asList(),正常 44 String[] strings = { "aa", "bb", "cc" }; 45 List<String> stringList = Arrays.asList(strings); 46 System.out.print("1、String类型数组使用asList(),正常: "); 47 for (String str : stringList) { 48 System.out.print(str + " "); 49 } 50 System.out.println(); 51 52 // 2、对象类型(Integer)的数组使用asList(),正常 53 Integer[] integers = new Integer[] { 1, 2, 3 }; 54 List<Integer> integerList = Arrays.asList(integers); 55 System.out.print("2、对象类型的数组使用asList(),正常: "); 56 for (int i : integerList) { 57 System.out.print(i + " "); 58 } 59 System.out.println(); 60 61 // 3、基本数据类型的数组使用asList(),出错 62 int[] ints = new int[] { 1, 2, 3 }; 63 List intList = Arrays.asList(ints); 64 System.out.print("3、基本数据类型的数组使用asList(),出错(输出的是一个引用,把ints当成一个元素了):"); 65 for (Object o : intList) { 66 System.out.print(o.toString()); 67 } 68 System.out.println(); 69 70 System.out.print(" " + "这样遍历才能正确输出:"); 71 int[] ints1 = (int[]) intList.get(0); 72 for (int i : ints1) { 73 System.out.print(i + " "); 74 } 75 System.out.println(); 76 77 // 4、当更新数组或者List,另一个将自动获得更新 78 System.out.print("4、当更新数组或者List,另一个将自动获得更新: "); 79 integerList.set(0, 5); 80 for (Object o : integerList) { 81 System.out.print(o + " "); 82 } 83 for (Object o : integers) { 84 System.out.print(o + " "); 85 } 86 System.out.println(); 87 88 } 89 }
四:面向对象
一、简介
1. 概念:面向对象也即OOP(Object Oriented Programming),是一种编程思想,它以对象作为基本的单元来构建系统,具有三大特征和五大原则。
2. 三大特征:
1. 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,提高安全性。
2. 继承:提高代码复用性,是实现多态的前提。
3. 多态:父类或接口定义的引用变量指向子类或具体实现类的实例对象,提高了代码的拓展性。
3. 五大原则
1. 单一职责原则SRP(Single Responsibility Principle):类的功能要单一。
2. 开放封闭原则OCP(Open-Close Principle):扩展开放,修改关闭。
3. 里式替换原则LSP(the Liskov Substitution Principle LSP):子类可以替换父类出现在父类能够出现的任何地方。
4. 依赖倒置原则DIP(the Dependency Inversion Principle DIP):高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
5. 接口分离原则ISP(the Interface Segregation Principle ISP):设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。
二、封装
1. 核心思想:隐藏细节,保护数据安全。
2. 访问权限
3. 封装代码实现
1 public class Encapsulation { 2 // 1.成员属性私有化 3 private String name; 4 private String pwd; 5 6 // 2.提供getter和setter方法来访问 7 public String getName() { 8 return name; 9 } 10 11 public void setName(String name) { 12 this.name = name; 13 } 14 15 public String getPwd() { 16 return pwd; 17 } 18 19 public void setPwd(String pwd) { 20 this.pwd = pwd; 21 } 22 } 23 24 class TestEncapsulation { 25 public static void main(String[] args) { 26 Encapsulation test = new Encapsulation(); 27 // 3.通过setter方法设置属性值 28 test.setName("封装"); 29 test.setPwd("666"); 30 // 4.通过getter方法获取值 31 System.out.println("姓名:" + test.getName() + " -- 密码:" + test.getPwd()); 32 33 } 34 }
三、方法的重载和重写
1. 方法的重载:方法名相同,参数列表不同
2. 方法的重写:方法名、返回值类型、参数列表都相同,构造方法和使用final、static修饰的方法不能被重写
3. 方法重载和重写代码实现
1 package pers.mj; 2 3 public interface Override { 4 /** 5 * 方法的重载:方法名相同,参数列表不同 6 */ 7 public void query(int id); 8 9 public int query(int id, String username); 10 11 } 12 13 class Test implements Override { 14 /** 15 * 方法的重写:方法的所有东西都一样,只有方法实体不同。 16 */ 17 public void query(int id) { 18 System.out.println("我重写了接口的方法"); 19 20 } 21 22 public int query(int id, String username) { 23 System.out.println("我也可以重写父类的方法"); 24 return 0; 25 } 26 27 }
四、继承
1. 核心思想:解决代码冗余,提高代码的复用性
2. 继承关系:满足is-a的关系,父类更通用,子类更具体。
3. 继承代码实现
1 /** 2 * 1. 将类中重复的部分提取成为父类 3 */ 4 public class Animal { 5 private String name; 6 private String food; 7 8 public Animal(String name, String food) { 9 this.name = name; 10 this.food = food; 11 } 12 13 public void eat() { 14 System.out.println(name + "正在吃" + food); 15 } 16 } 17 18 /** 19 * 2. 子类继承父类,对父类进行扩展 20 */ 21 public class Cat extends Animal { 22 23 public Cat(String name, String food) { 24 super(name, food); 25 } 26 } 27 public class Dog extends Animal{ 28 29 public Dog(String name, String food) { 30 super(name, food); 31 } 32 } 33 34 /** 35 * 3. 测试 36 */ 37 public class TestExtends{ 38 public static void main(String[] args) { 39 Animal cat = new Cat("三三", "鱼"); 40 cat.eat(); 41 Animal dog = new Dog("二哈", "香肠"); 42 cat.eat(); 43 } 44 }
五、多态
1. 核心思想:提高代码可维护性和可扩展性
2. 实现多态的三个必要条件:继承、重写、父类引用指向子类对象(向下转型)
3. 多态的实现方式:重写、接口、抽象类和抽象方法
4. 多态代码实现
1 /** 2 * 1. 创建动物类,定义动物吃什么的方法 3 */ 4 class Animals { 5 private String name; 6 private String food; 7 8 public Animals(String name, String food) { 9 super(); 10 this.name = name; 11 this.food = food; 12 } 13 14 public void eat() { 15 System.out.println(this.name + "会吃" + this.food); 16 } 17 } 18 20 /** 21 * 2. 创建Cat类来实现吃的功能 22 */ 23 class Cat extends Animals{ 24 public Cat(String name, String food) { 25 super(name, food); 26 } 27 28 @Override 29 public void eat() { 30 super.eat(); 31 } 32 } 33 35 /** 36 * 3. 通过向上转型和向下转型实现多态 37 */ 38 public class Test01 { 39 public static void main(String[] args) { 40 // 向下转型 41 Animals animals = new Cat("三三", "鱼"); 42 animals.eat(); 43 // 向上转型 44 Cat cat = (Cat) animals; 45 cat.eat(); 46 } 47 }
六、抽象类
1. 核心思想:让代码有更强的可扩展性
2. 特点
1. 抽象类不能实例化对象。
2. 如果一个类包含抽象方法,那么该类必须是抽象类
3. 任何子类必须重写父类的抽象方法(具体实现),或者声明自身为抽象类
4. 抽象类中的抽象方法只有方法声明,没有方法体
5. 构造方法和static修饰的方法不能声明为抽象方法
3. 抽象类代码实现
1 /** 2 * 1. 创建员工抽象类 3 */ 4 abstract class Employees { 5 // 成员变量 6 private String name; 7 private String address; 8 private Integer number; 9 10 // 构造方法 11 public Employees(String name, String address, Integer number) { 12 System.out.println("Employees.Employees()"); 13 this.name = name; 14 this.address = address; 15 this.number = number; 16 } 17 18 // 定义信息抽象函数 19 public abstract void call(); 20 21 // 省略getter 和 setter方法 22 ...... 23 } 24 } 25 26 class Salary extends Employees { 27 private Double salary; 28 29 public Salary(String name, String address, Integer number, Double salary) { 30 super(name, address, number); 31 this.salary = salary; 32 System.out.println("Salary.Salary()"); 33 } 34 35 // 2. 重写父类的抽象方法 36 @Override 37 public void call() { 38 System.out.println(super.getNumber() + "是" + super.getName() + "的电话,他住在" + 39 super.getAddress() + "他现在的工资是" + this.salary); 40 } 41 } 42 43 public class Test { 44 public static void main(String[] args) { 45 // 3. 抽象类的对象必须由子类去实例化 46 Employees emp = new Salary("孙悟空", "花果山", 1234, 222.66); 47 emp.call(); 48 } 49 }
七、接口
1. 核心思想:让代码有更强的可扩展性
2. 特点
1. 接口不能实例化对象,没有构造方法
2. 接口中的方法只能是抽象方法,默认使用public abstract修饰
3. 接口中的变量只能是常量,默认使用public static final修饰
4. 接口支持多继承,但接口不是被继承了,而是被实现了
3. 接口和抽象类的区别
1. 接口中的方法只能是抽象方法,而抽象类中的方法可以是普通方法,构造方法和抽象方法
2. 接口中的变量只能是常量,而抽象类中的方法可以是任意类型
3. 接口中不能含有静态代码块和静态方法,而抽象类中可以有
4. 一个类可以实现多个接口,但一个类只能继承一个抽象类
1 /** 2 * 1. 创建Animal接口 3 */ 4 interface Animal { 5 // 定义睡觉抽象方法 6 void sleep(); 7 8 // 定义吃饭抽象方法 9 void eat(); 10 } 11 12 /** 13 * 2. 创建Dog接口继承Animal接口 14 */ 15 interface Dog extends Animal { 16 // 定义游泳抽象方法 17 void swim(); 18 } 19 20 /** 21 * 3. 创建HaShiQi接口继承Dog和Animal接口,实现多继承 22 */ 23 interface HaShiQi extends Dog, Animal { 24 // 定义拆家抽象方法 25 void demolishedFamily(); 26 } 27 28 /** 29 * 4. 创建测试类来实现接口,并且复写所有抽象方法 30 */ 31 public class TestAnimal implements HaShiQi { 32 33 @Override 34 public void swim() { 35 System.out.println("哈士奇会游泳"); 36 } 37 38 @Override 39 public void sleep() { 40 System.out.println("哈士奇会睡觉"); 41 } 42 43 @Override 44 public void eat() { 45 System.out.println("哈士奇喜欢吃苦瓜"); 46 } 47 48 @Override 49 public void demolishedFamily() { 50 System.out.println("哈士奇会拆家"); 51 } 52 53 public static void main(String[] args) { 54 // 使用多态实例化对象 55 HaShiQi dog = new TestAnimal(); 56 dog.eat(); 57 dog.sleep(); 58 dog.demolishedFamily(); 59 dog.swim(); 60 } 61 }
五:常用类
一、Number & Math 类:包含了数据类型转换和用于执行基本数学运算的属性和方法。
1. 常用方法
2. 代码实现
1 package pers.mj; 2 3 import java.util.Random; 5 import org.junit.Test; 6 7 public class TestMathAndNumber { 8 @Test 9 public void testMath() { 10 // 获取绝对值 11 System.out.println(Math.abs(-10)); // 10 12 // 求平方根 13 System.out.println(Math.sqrt(4)); // 2.0 14 // 求幂 15 System.out.println(Math.pow(2, 5)); // 32.0 16 // 自然对数 17 System.out.println(Math.log(100)); // 4.6~ 18 // 向上取整 19 System.out.println(Math.floor(2.80)); // 2.0 20 // 向下取整 21 System.out.println(Math.ceil(2.25)); // 3.0 22 // 四舍五入 23 System.out.println(Math.round(2.25)); // floor(2.25+0.5)=2 24 // 生成指定范围的随机数 25 System.out.println(randomNumber(1000, 9999)); 26 27 } 28 29 public static Integer randomNumber(Integer minNum,Integer maxNum) { 30 return new Random().nextInt((maxNum - minNum + 1) + minNum); 31 } 32 }
二、String 类
1. 常用方法
2. 常用操作
1 package pers.mj; 2 3 import org.junit.Test; 4 5 public class TestString { 6 @Test // 基本操作 7 public void testBase() { 8 // 定义字符串 9 String str = " 你再惹我,我给你一个大嘴巴子 "; 10 // 获取字符串长度 11 System.out.println(str.length()); 12 // 忽略字符串两边的空行 13 System.out.println(str.trim()); 14 // 获取指定索引出的字符 15 System.out.println(str.charAt(3)); 16 // 将字符串转换并存储在字符数组中 17 char[] chardst = new char[1024]; 18 str.getChars(0, 7, chardst, 0); 19 System.out.println(chardst); 20 21 } 22 23 @Test // 字符串比较 24 public void testCompare() { 25 String str1 = "elapant"; 26 String str2 = "ELEPANT"; 27 String str3 = "Apple"; 28 String str4 = "apple"; 29 // compareTo()方法:不忽略大小写 30 if (str1.compareTo(str2) > 0) { 31 System.out.println(str1 + ">" + str2); 32 } else if (str1.compareTo(str2) == 0) { 33 System.out.println(str1 + "=" + str2); 34 } else { 35 System.out.println(str1 + "<" + str2); 36 } 37 38 // compareToIgnoreCase()方法:忽略大小写 39 if (str1.compareToIgnoreCase(str2) > 0) { 40 System.out.println(str1 + ">" + str2); 41 } else if (str1.compareToIgnoreCase(str2) == 0) { 42 System.out.println(str1 + "=" + str2); 43 } else { 44 System.out.println(str1 + "<" + str2); 45 } 46 47 // equals()方法:不忽略大小写 48 if (str3.equals(str4)) { 49 System.out.println(str3 + "=" + str4); 50 } else { 51 System.out.println(str3 + "!=" + str4); 52 } 53 54 // equalsIgnoreCase()方法:忽略大小写 55 if (str3.equalsIgnoreCase(str4)) { 56 System.out.println(str3 + "=" + str4); 57 } else { 58 System.out.println(str3 + "!=" + str4); 59 } 60 } 61 62 @Test // 字符串与其他数据类型转换 63 public void testConvert() { 64 /** 65 * 将字符串转为其他数据类型 66 */ 67 boolean bool = Boolean.getBoolean("false"); 68 Integer integer = Integer.getInteger("20"); 69 byte parseByte = Byte.parseByte("20"); 70 float parseFloat = Float.parseFloat("20.2"); 71 double parseDouble = Double.parseDouble("20.2"); 72 Long long1 = Long.getLong("20"); 73 74 /** 75 * 将其他数据类型转为字符串:valueOf 76 */ 77 String all = String.valueOf(bool); 78 79 } 80 81 @Test // 字符串查找 82 public void testFind() { 83 // 定义字符串 84 String str = "How qi bocome handsome like qi ge"; 85 86 // indexOf(string, index):查找首个字符串出现的位置 87 System.out.println(str.indexOf("qi", 4)); 88 89 // lastIndexOf(string, index):查找最后一个字符串出现的位置 90 System.out.println(str.lastIndexOf("qi", 10)); 91 92 } 93 94 @Test // 字符串截取、拼接、替换和修改 95 public void testMain() { 96 // 定义字符串 97 String str = "How to cut and split strings"; 98 99 // 截取指定索引范围的字符串:substring(startIndex, endIndex) 100 System.out.println(str.substring(0, 10)); 101 102 // 按照指定正则表达式拆分字符串:split(regex) 103 String[] split = str.split(","); 104 for (String string : split) { 105 System.err.println(string); 106 } 107 108 // 拼接字符串:concat(str) 109 System.out.println(str.concat("I'm OK") + "或者是" + str + "这样也可以拼接"); 110 111 // 字符串替换:replace(oldStr, newStr) 112 System.out.println(str.replace("I'm OK", "I'm new string")); 113 } 114 }
三、时间日期类
1 package pers.mj; 2 3 import java.text.DateFormat; 4 import java.text.SimpleDateFormat; 5 import java.time.LocalDateTime; 6 import java.time.format.DateTimeFormatter; 7 import java.time.format.FormatStyle; 8 import java.util.Calendar; 9 import java.util.Date; 10 11 import org.junit.Test; 12 13 public class TestDate { 14 @Test // 日期实例化 15 public void testDate() { 16 // Date类:使用无参构造创建 17 Date date = new Date(); 18 System.out.println(date.getTime()); // 时间戳:1592013149642 19 20 // Calendar类:静态方法获取实例 21 Calendar instance = Calendar.getInstance(); 22 // 获取年月日:MONTH默认0-11 23 System.out.println(instance.get(Calendar.YEAR) + "年 " + instance.get(Calendar.MONTH) + "月 " 24 + instance.get(Calendar.DATE) + "日"); 25 // 设置年月日 26 instance.set(2020, 6, 13); 27 System.out.println(instance.get(Calendar.YEAR) + "年 " + instance.get(Calendar.MONTH) + "月 " 28 + instance.get(Calendar.DATE) + "日"); 29 30 // LocalDateTime类:新增 31 // 使用静态方法now()获取当前时间日期 32 LocalDateTime ldt = LocalDateTime.now(); 33 // 使用plusXxx(int x)增加指定字段的值 34 ldt.plusDays(1); // Day字段的值+1 35 // 使用minusXxx(int x)方法减少指定的字段的值 36 ldt.minusHours(1); // Hours字段的值-1 37 } 38 39 @Test // 日期格式化 40 public void testDateFormat() { 41 // DateFormat类:预定义格式,format(date)方法用来格式化 42 System.out.println(DateFormat.getDateInstance().format(new Date())); // 2020年6月13日 43 System.out.println(DateFormat.getTimeInstance().format(new Date())); // 上午11:13:42 44 System.out.println(DateFormat.getDateTimeInstance().format(new Date())); // 2020年6月13日 上午11:13:42 45 46 // SimpleDateFormat类:自定义格式自定日格式化日期,format(date)方法用来格式化 47 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 48 System.out.println(simpleDateFormat.format(new Date())); 49 50 // DateTimeFormatter类:前两者的结合体 51 // 预定义格式 52 DateTimeFormatter ofLocalizedDateTime = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, 53 FormatStyle.FULL); 54 // 自定义格式 55 DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("y-M-d H:m:s"); 56 57 // 实例化日期 58 LocalDateTime now = LocalDateTime.now(); 59 60 System.out.println(ofLocalizedDateTime.format(now)); 61 System.out.println(ofPattern.format(now)); 62 63 } 64 }
四、正则表达式
1. 概念
1. Pattern类:编译正则表达式,必须通过compile(pattern) 创建
2. Matcher类:对输入字符串进行解释和匹配操作的引擎,必须通过 pattern.matcher(str) 创建。
3. 捕获组:把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建,从左至右计算((A)(B(C))) 。
2. 操作
1. 常用方法
2. 常用方法代码实现
1 package pers.mj; 2 3 import java.util.regex.Pattern; 4 5 public class TestRegex { 6 /*** 7 * 校验密码强度 8 * 9 * @param pattern 10 * @return 11 */ 12 public static boolean passwordRegex(String str) { 13 boolean flag = false; 14 flag = Pattern.matches("^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$", str); 15 16 return flag; 17 } 18 19 /*** 20 * 校验中文 21 * 22 * @param pattern 23 * @return 24 */ 25 public static boolean chineseRegex(String str) { 26 boolean flag = true; 27 flag = Pattern.matches("^[\u4e00-\u9fa5]{0,}$", str); 28 return flag; 29 } 30 31 /*** 32 * 由数字、26个英文字母或下划线组成的字符串 33 * 34 * @param pattern 35 * @return 36 */ 37 public static boolean pointRegex(String str) { 38 boolean flag = true; 39 flag = Pattern.matches("^\w+$", str); 40 return flag; 41 } 42 43 /*** 44 * 校验E-Mail 地址 45 * 46 * @param pattern 47 * @return 48 */ 49 public static boolean emailRegex(String str) { 50 boolean flag = true; 51 flag = Pattern.matches( 52 "[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?", 53 str); 54 return flag; 55 } 56 57 /*** 58 * 校验身份证号码 下面是身份证号码的正则校验。15 或 18位。 59 * 60 * @param pattern 61 * @return 62 */ 63 public static boolean idCardRegex(String str) { 64 boolean flag = true; 65 if (str.length() == 15) { 66 flag = Pattern.matches("^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$", str); 67 } else if (str.length() == 18) { 68 flag = Pattern.matches("^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$", 69 str); 70 } else { 71 flag = false; 72 } 73 74 return flag; 75 } 76 77 /*** 78 * 校验日期 “yyyy-mm-dd“ 格式的日期校验,已考虑平闰年。 79 * 80 * @param pattern 81 * @return 82 */ 83 public static boolean yearRegex(String str) { 84 boolean flag = true; 85 flag = Pattern.matches( 86 "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|" 87 + "(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$", 88 str); 89 return flag; 90 } 91 92 /*** 93 * 校验金额 金额校验,精确到2位小数。 94 * 95 * @param pattern 96 * @return 97 */ 98 public static boolean amountRegex(String str) { 99 boolean flag = true; 100 flag = Pattern.matches("^[0-9]+(.[0-9]{2})?$", str); 101 return flag; 102 } 103 104 /*** 105 * 校验手机号 下面是国内 13、15、18开头的手机号正则表达式。(可根据目前国内收集号扩展前两位开头号码) 106 * 107 * @param pattern 108 * @return 109 */ 110 public static boolean telRegex(String str) { 111 boolean flag = true; 112 flag = Pattern.matches("^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$", str); 113 return flag; 114 } 115 116 /*** 117 * 判断IE的版本 118 * 119 * @param pattern 120 * @return 121 */ 122 public static boolean ieVersionRegex(String str) { 123 boolean flag = true; 124 flag = Pattern.matches("^.*MSIE [5-8](?:\.[0-9]+)?(?!.*Trident\/[5-9]\.0).*$", str); 125 return flag; 126 } 127 128 /*** 129 * 校验IP-v4地址 130 * 131 * @param pattern 132 * @return 133 */ 134 public static boolean ipV4Regex(String str) { 135 boolean flag = true; 136 flag = Pattern.matches( 137 "\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", 138 str); 139 return flag; 140 } 141 142 /*** 143 * 校验IP-v6地址 144 * 145 * @param pattern 146 * @return 147 */ 148 public static boolean ipV6Regex(String str) { 149 boolean flag = true; 150 flag = Pattern.matches( 151 "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" 152 + "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]" 153 + "{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:" 154 + "((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]" 155 + "{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}" 156 + "[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}" 157 + "[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))", 158 str); 159 return flag; 160 } 161 }
六:集合
一、简介
1. 作用:存储引用类型数据,长度可以动态的改变,解决了存储数据数量不确定的问题。
2. 架构:Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。
二、Collection 集合体系
1. 架构图:存储一组不唯一,无序的对象。
2. 常用方法
3. 不同集合的使用场景
4. 集合常用方法代码实现
1 /** 2 * 创建学生类 3 */ 4 class Student { 5 // 学号 6 private Integer id; 7 // 姓名 8 private String name; 9 10 public Student(Integer id, String name) { 11 this.id = id; 12 this.name = name; 13 } 14 15 @Override 16 public String toString() { 17 return "Student [id=" + id + ", name=" + name + "]"; 18 } 19 20 } 21 22 public class TestCollection { 23 public static void main(String[] args) { 24 // 1. 创建集合存储String类型数据 25 List<String> list = new ArrayList<String>(); 26 27 // 2.向集合中添加元素 28 list.add("猪猪侠"); 29 list.add("超人强"); 30 list.add("波比"); 31 list.add("小菲菲"); 32 33 // 3. 遍历集合 34 // 3.1普通for循环 35 String[] strArray = new String[list.size()]; 36 list.toArray(strArray); // 将集合转换为数组 37 for (int i = 0; i < strArray.length; i++) { 38 System.out.println(strArray[i]); 39 } 40 41 // 3.2 foreach循环 42 for (String str : list) { 43 System.out.println(str); 44 } 45 46 // 3.3 迭代器遍历 47 Iterator<String> iterator = list.iterator(); 48 while (iterator.hasNext()) { // hasNext():判断指针后是否有下一个元素 49 System.out.println(iterator.next()); // next():返回指针后的元素 50 } 51 52 // 4. 判断集合中是否包含某元素 53 System.out.println(list.contains("小菲菲")); // true 54 55 // 5. 判断集合是否为空 56 System.out.println(list.isEmpty()); // false 57 58 // 6. 清除集合中所有元素 59 list.clear(); 60 System.out.println(list.isEmpty()); // true 61 System.out.println("---------------------------------------------------"); 62 63 64 // 创建集合存储对象类型数据 65 List<Student> list2 = new ArrayList<Student>(); 66 67 // 向集合中添加对象类型数据 68 list2.add(new Student(1, "张三")); 69 list2.add(new Student(2, "李四")); 70 71 // foreach遍历集合 72 for (Student student : list2) { 73 System.out.println(student); 74 } 75 76 // 迭代器遍历集合 77 Iterator<Student> iterator2 = list2.iterator(); 78 while (iterator2.hasNext()) { 79 Student student = iterator2.next(); 80 System.out.println(student); 81 } 82 } 83 }
三、Map 集合体系
1. 架构图:存储键值对象,提供key(键)到value(值)的映射。
2. 常用方法
3. 常用操作代码实现
1 import java.util.HashMap; 2 import java.util.Iterator; 3 import java.util.Map; 4 import java.util.Map.Entry; 5 6 import javax.enterprise.inject.New; 7 8 class Teacher { 9 private String name; 10 private Integer age; 11 12 public Teacher(String name, Integer age) { 13 this.name = name; 14 this.age = age; 15 } 16 17 @Override 18 public String toString() { 19 return "Teacher [name=" + name + ", age=" + age + "]"; 20 } 21 22 } 23 24 public class TestMap { 25 public static void main(String[] args) { 26 // 1. 创建Map集合存储学号和姓名 27 Map<Integer, String> map = new HashMap<Integer, String>(); 28 29 // 2. 向map集合中添加元素 30 map.put(1, "张三"); 31 map.put(2, "李四"); 32 map.put(3, "王五"); 33 34 // 3. 遍历map集合 35 // 3.1 通过map.keySet()遍历集合 36 for (Integer key : map.keySet()) { 37 System.out.println("key=" + key + " value=" + map.get(key)); 38 } 39 40 // 3.2 通过迭代器遍历集合 41 Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator(); 42 while (iterator.hasNext()) { 43 Map.Entry<Integer, String> entry = iterator.next(); 44 System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); 45 } 46 47 // 3.3 通过map.entrySet()遍历集合 48 for (Entry<Integer, String> entry : map.entrySet()) { 49 System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); 50 } 51 52 // 4. 判断集合中是否包含指定键 53 System.out.println(map.containsKey("1")); // true 54 System.out.println(map.containsValue("list")); // false 55 56 // 5. 判断集合是否为空 57 System.out.println(map.isEmpty()); // false 58 59 // 6. 清除集合中所有元素 60 map.clear(); 61 System.out.println(map.isEmpty()); // true 62 63 System.out.println("----------------------------------------"); 64 65 // 1. 创建Map集合存储对象类型数据 66 Map<Integer, Teacher> map2 = new HashMap<Integer, Teacher>(); 67 68 // 2. 向Map集合中添加对象类型数据 69 map2.put(1, new Teacher("张三", 18)); 70 map2.put(2, new Teacher("李四", 19)); 71 map2.put(3, new Teacher("王五", 20)); 72 73 // 3. 遍历集合 74 // 3.1 通过map.keySet()遍历:普遍使用 75 for (Integer key : map2.keySet()) { 76 System.out.println("key=" + key + " value=" + map2.get(key)); 77 } 78 79 // 3.2 通过迭代器遍历集合 80 Iterator<Entry<Integer, Teacher>> iterator2 = map2.entrySet().iterator(); 81 while (iterator2.hasNext()) { 82 Entry<Integer, Teacher> entry = iterator2.next(); 83 System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); 84 } 85 86 // 3.3 通过map.entrySet()遍历集合:推荐使用 87 for (Entry<Integer, Teacher> entry : map2.entrySet()) { 88 System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); 89 } 90 } 91 }
七:IO流
一、
1. 流的概念:流是有起点和终点的一组有顺序的字节集合,作用是进行数据传输
2. 流的分类
1. 按照数据流向不同可以分为输入输出流;
2. 按照处理数据单位不同可以分为字节流和字符流
3. 输入流和输出流的作用
1. 输入流:程序从数据源读取数据
2. 输出流:将数据从程序中写入指定文件
4. 字节流和字符流的作用
1. 字节流:以字节为单位处理所有类型数据
2. 字符流:以字符为单位处理纯文本文件
二、体系结构
三、常用方法
四、常用方法实现文本文件复制
1 import java.io.FileInputStream; 2 import java.io.FileNotFoundException; 3 import java.io.FileOutputStream; 4 import java.io.FileReader; 5 import java.io.FileWriter; 6 import java.io.IOException; 7 8 /** 9 * 1. 文本文件复制 10 * @author DELL 11 * 12 */ 13 public class TestIO { 14 public static void main(String[] args) { 15 // 要读取的文件 16 String src = "E:/Workspaces1/Demo/src/TestFile.java"; 17 // File src = new File("路径"); 18 // 要写入的文件 19 String dest = "d:/test.java"; 20 21 // 1.1 一次复制一个字节 22 copyFile1(src, dest); 23 // 1.2 一次复制一个字节数组 24 copyFile2(src, dest); 25 26 // 2.1 一次复制一个字符 27 copyFile3(src, dest); 28 // 2.2 一次复制一个字符数组 29 copyFile4(src, dest); 30 } 31 32 // 1. 一次复制一个字节,异常处理,手动关闭流 33 public static void copyFile1(String srcFileName, String destFileName) { 34 FileInputStream fis = null; 35 FileOutputStream fos = null; 36 try { 37 fis = new FileInputStream(srcFileName); 38 fos = new FileOutputStream(destFileName); 39 int cc = fis.read(); 40 while (cc != -1) { 41 // 一次写入一个字节 42 fos.write(cc); 43 // 一次写入一个字节 44 cc = fis.read(); 45 } 46 } catch (FileNotFoundException e) { 47 e.printStackTrace(); 48 } catch (IOException e) { 49 e.printStackTrace(); 50 } finally { 51 if (fos != null) { 52 try { 53 fos.close(); 54 } catch (IOException e) { 55 e.printStackTrace(); 56 } 57 } 58 if (fis != null) { 59 try { 60 fis.close(); 61 } catch (IOException e) { 62 e.printStackTrace(); 63 } 64 } 65 } 66 } 67 68 // 2. 一次复制一个字节数组,异常处理,自动关闭流 69 public static void copyFile2(String srcFileName, String destFileName) { 70 // 自动关闭流 71 try ( 72 FileInputStream fis = new FileInputStream(srcFileName); 73 FileOutputStream fos = new FileOutputStream(destFileName); 74 ) { 75 byte[] bytes = new byte[1024]; 76 int len = fis.read(bytes); 77 while (len != -1) { 78 // 一次写入一个字节数组 79 fos.write(bytes, 0, len); 80 // 一次读取一个字节数组 81 len = fis.read(bytes); 82 } 83 } catch (FileNotFoundException e) { 84 e.printStackTrace(); 85 } catch (IOException e) { 86 e.printStackTrace(); 87 } 88 } 89 90 // 3. 一次复制一个字符,异常处理,自动关闭流 91 public static void copyFile3(String srcFileName, String destFileName) { 92 try ( 93 FileReader fr = new FileReader(srcFileName); 94 FileWriter fw = new FileWriter(destFileName); 95 ){ 96 int cc = fr.read(); 97 while (cc != -1) { 98 // 一次写入一个字符 99 fw.write(cc); 100 // 一次读取一个字符 101 cc = fr.read(); 102 } 103 } catch (FileNotFoundException e) { 104 e.printStackTrace(); 105 } catch (Exception e) { 106 e.printStackTrace(); 107 } 108 } 109 110 // 4. 一次复制一个字符数组,异常处理,手动关闭流 111 public static void copyFile4(String srcFileName, String destFileName) { 112 FileReader fr = null; 113 FileWriter fw = null; 114 try { 115 fr = new FileReader(srcFileName); 116 fw = new FileWriter(destFileName); 117 char[] cbuf = new char[1024]; 118 int len = fr.read(cbuf); 119 while (len != -1) { 120 // 一次写入一个字符数组 121 fw.write(cbuf); 122 // 一次读取一个字符数组 123 len = fr.read(cbuf); 124 } 125 } catch (FileNotFoundException e) { 126 e.printStackTrace(); 127 } catch (IOException e) { 128 e.printStackTrace(); 129 } finally { 130 if (fw != null) { 131 try { 132 fw.close(); 133 } catch (IOException e) { 134 e.printStackTrace(); 135 } 136 } 137 if (fr != null) { 138 try { 139 fr.close(); 140 } catch (IOException e) { 141 e.printStackTrace(); 142 } 143 } 144 } 145 } 146 }
五、序列化和反序列化
1. 序列化和反序列化的概念
1. 对象序列化:把对象转换为字节序列(二进制数据)的过程
2. 对象反序列化:把字节序列恢复为对象的过程
2. 什么情况下需要序列化
1. 将对象保存到文件或数据库中时
2. 使用套接字在网上传送对象时
3. 通过RMI传输对象时
3. 如何实现序列化
1. 创建类实现Serializable接口
2. 指定serialVersionUID序列号
3. 使用对象输出流(ObjectOutputStream)将对象保存到指定位置
4. 使用writerObject()方法将对象写入到文件中
4. 哪些属性不能被序列化
1. 使用transient修饰的属性
2. 使用static修饰的属性
5. 序列化和反序列化代码实现
1 // 1. 创建类实现Serializable接口 2 class People implements Serializable { 3 4 // 2. 指定序列号 5 private static final long serialVersionUID = 1L; 6 // 静态字段 7 private static String id = "2019"; 8 // transient关键字修饰的字段 9 private transient String name; 10 11 private Integer age; 12 13 public String getName() { 14 return name; 15 } 16 17 public void setName(String name) { 18 this.name = name; 19 } 20 21 public Integer getAge() { 22 return age; 23 } 24 25 public void setAge(Integer age) { 26 this.age = age; 27 } 28 29 @Override 30 public String toString() { 31 return "People [name=" + name + ", age=" + age + "]"; 32 } 33 34 } 35 36 public class Test { 37 public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { 38 serializePeople(); 39 deserializePeople(); 40 } 41 42 /** 43 * 序列化 44 */ 45 public static void serializePeople() throws FileNotFoundException, IOException { 46 People p = new People(); 47 p.setName("张三"); 48 p.setAge(18); 49 // 3. 使用对象输出流将对象保存到指定位置 50 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:/test.txt"))); 51 // 4. 将对象写入文件 52 oos.writeObject(p); 53 System.out.println("对象序列化成功!!"); 54 oos.close(); 55 } 56 57 /** 58 * 反序列化 59 */ 60 public static People deserializePeople() throws ClassNotFoundException, IOException { 61 // 使用对象输入流从指定位置读取对象 62 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:/test.txt"))); 63 // 读取对象 64 People p = (People) ois.readObject(); 65 System.out.println("对象反序列化成功!!"); 66 return p; 67 68 } 69 }
六、File 类常用方法
1 import java.io.File; 2 import java.io.FileFilter; 3 import java.io.IOException; 4 import java.text.SimpleDateFormat; 5 6 public class TestFile { 7 public static void main(String[] args) throws IOException { 8 // 1. 构造方法指明文件路径以及格式 9 File file = new File("D:\test2\test.txt"); 10 File file2 = new File("D:\test2"); 11 File file3 = new File("D:\test3"); 12 13 // 2.1 创建一个文件 14 file.createNewFile(); 15 // 2.2 创建一个单级目录 16 file2.mkdir(); 17 // 2.3 创建一个多级目录 18 file3.mkdirs(); 19 20 // 3.1 判断文件或文件夹是否存在 21 System.out.println(file.exists()); // true 22 // 3.2 判断是否为绝对路径 23 System.out.println(file.isAbsolute()); // true 24 // 3.3 判断是否为文件 25 System.out.println(file2.isFile()); // false 26 // 3.4 判断是否为目录 27 System.out.println(file2.isDirectory()); // true 28 // 3.5 判断是否为隐藏文件 29 System.out.println(file3.isHidden()); // false 30 31 // 4.1 获取文件或目录名称 32 System.out.println(file.getName()); 33 // 4.2 获取文件的绝对路径 34 System.out.println(file.getAbsolutePath()); 35 // 4.3 获取文件相对路径 36 System.out.println(file.getPath()); 37 // 4.4 获取文件父目录 38 System.out.println(file.getParent()); 39 // 4.5 获取文件大小 40 System.out.println(file.length()); 41 // 4.6 获取文件最后一次被修改时间 42 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 43 String updateTime = sdf.format(file.lastModified()); 44 System.out.println(updateTime); 45 46 // 5.1 返回此目录下的所有文件和目录 47 String [] fileString = file2.list(); 48 for (String str : fileString) { 49 System.out.println(str); 50 } 51 // 5.2 返回此目录下的所有文件 52 File [] files = file2.listFiles(); 53 for (File file4 : files) { 54 System.out.println(file4.getName()); 55 } 56 // 5.3 返回所有根目录 57 File [] files2 = File.listRoots(); 58 for (File file4 : files2) { 59 System.out.println(file4); 60 } 61 // 5.4 返回指定目录中符合过滤条件的文件和目录 62 File [] files3 = file2.listFiles(new FileFilter() { 63 64 @Override 65 public boolean accept(File pathname) { 66 while ("a.txt".equals(pathname.getName())){ 67 return true; 68 } 69 return false; 70 } 71 }); 72 for (File file4 : files3) { 73 System.out.println(file4.getName()); 74 } 75 } 76 }
八:多线程
一、简介
1. 线程和进程
1. 进程:操作系统中的应用程序,一个进程就是一个应用程序
2. 线程:CPU调度的最小单元,进程的一个执行流
2. 上下文切换
1. 上下文切换:CPU从一个线程或进程切换到另一个进程或线程;
2. 多线程程序并不是同时进行的,由于CPU的执行速度太快,CPU会在不同的线程之间快速的切换执行;
二、实现方式
1 import java.util.concurrent.Callable; 2 import java.util.concurrent.FutureTask; 3 4 /** 5 * 1. 创建多线程的三种方式 6 * 1. 继承Thread类 7 * 8 * 2. 实现Runnable接口 9 * 1. 方式一:创建类实现Runnable接口 10 * 1. 创建类实现Runnable接口 11 * 2. 重写run()方法 12 * 3. 使用Thread类的构造方法实例化实现Runnable接口的类对象 13 * 4. 开启线程 14 * 15 * 2. 方式二:使用匿名内部类 16 * 1. 使用Thread类的构造方法创建一个Runnable接口的代理对象 17 * 2. 重写run()方法 18 * 2. 开启线程 19 * 20 * 3. 实现Callable接口 21 * 1. 方式一:创建类实现Callable接口 22 * 1. 创建类实现Callable接口 23 * 2. 重写call()方法 24 * 3. 使用Thread类的构造方法实例化FutureTask对象 25 * 4. 使用FutureTask类的构造方法实例化实现了Callable接口的类对象 26 * 5. 开启线程 27 * 28 * 2. 方式二:使用匿名内部类 29 * 1. 使用Thread类的构造方法实例化FutureTask对象 30 * 2. 使用FutureTask类的构造方法创建Callable接口的代理对象 31 * 3. 重写call()方法 32 * 4. 开启线程 33 * 34 * 2. 三种方式的优缺点 35 * 1. 继承了Thread类 36 * 1. 优点:代码书写简单 37 * 2. 缺点:由于Java的单继承性,代码的耦合度比较高 38 * 39 * 2. 实现了Runnable接口和Callable接口 40 * 1. 方式一: 41 * 1. 优点:代码的可扩展性更强 42 * 2. 缺点:没有缺点 43 * 44 * 2. 方式二: 45 * 1. 优点:代码书写简单 46 * 2. 缺点:只适合线程使用一次的时候 47 */ 48 49 50 /** 51 * 1. 继承Thread类 52 */ 53 class Thread1 extends Thread{ 54 public static void test() { 55 for (int i = 0; i < 100; i++) { 56 System.out.println("继承Thread类执行的第" + i + "次"); 57 } 58 } 59 } 60 61 /** 62 * 2. 实现Runnable接口 63 */ 64 class Thread2 implements Runnable{ 65 66 @Override 67 public void run() { 68 for (int i = 0; i < 100; i++) { 69 System.out.println("实现Runnable接口方式一执行的第" + i + "次"); 70 } 71 } 72 } 73 74 /** 75 * 3. 实现Callable接口 76 */ 77 class Thread3 implements Callable<Integer>{ 78 @Override 79 public Integer call() throws Exception { 80 int i = 0; 81 for (; i < 100; i++) { 82 System.out.println("实现Callable接口方式一执行的第" + i + "次"); 83 } 84 return i; 85 } 86 } 87 88 public class TestThread { 89 public static void main(String[] args) { 90 // 1. 测试继承Thread类 91 Thread1 thread1 = new Thread1(); 92 thread1.start(); 93 Thread1.test(); 94 95 96 // 2. 测试实现Runnable接口 97 // 2.1 方式一 98 new Thread(new Thread2()).start(); 99 100 // 2.2 方式二 101 new Thread(new Runnable() { 102 @Override 103 public void run() { 104 for (int i = 0; i < 100; i++) { 105 System.out.println("实现Runnable接口方式一执行的第" + i + "次"); 106 } 107 } 108 }).start(); 109 110 111 // 3. 测试实现Callable接口 112 // 3.1 方式一 113 new Thread(new FutureTask<Integer>(new Thread3() { 114 }), "方式三").start();; 115 116 // 3.2 方式二 117 new Thread(new FutureTask<Integer>(new Callable<Integer>() { 118 @Override 119 public Integer call() throws Exception { 120 int i = 0; 121 for (; i < 100; i++) { 122 System.out.println("实现Runnable接口方式二执行的第" + i + "次"); 123 } 124 return i; 125 } 126 })).start();; 127 } 128 }
三、常用方法
1. 方法图
2. 常用方法代码实现
1 public class TestThreadMethod { 2 public static void main(String[] args) { 3 Thread thread = new Thread(new Runnable() { 4 @Override 5 public void run() { 6 for (int i = 0; i < 100; i++) { 7 // 获取正在执行的线程对象的引用 8 System.out.println(Thread.currentThread().getName() + "执行的第" + i + "次"); 9 } 10 } 11 }); 12 // 1. 开启线程 13 thread.start(); 14 15 16 // 2. 设置 17 // 2.1 设置该线程名称 18 thread.setName("线程1号"); 19 // 2.2 设置该线程为守护线程:main方法结束之后该线程停止 20 //thread.setDaemon(true); 21 // 2.3 设置该线程的优先级 22 thread.setPriority(7); 23 24 25 // 3. 获取 26 // 3.1 获取线程名称 27 System.out.println(thread.getName()); // 线程1号 28 // 3.2 获取线程标识符 29 System.out.println(thread.getId()); // 13 30 // 3.3 获取线程优先级 31 System.out.println(thread.getPriority()); // 7 32 // 3.4 获取线程状态 33 System.out.println(thread.getState()); // RUNNABLE 34 // 3.5 获取线程所在线程组 35 System.out.println(thread.getThreadGroup()); // java.lang.ThreadGroup[name=main,maxpri=10] 36 37 38 // 4. 判断 39 // 4.1 判断线程是否中断 40 System.out.println(thread.isInterrupted()); // false 41 // 4.2 判断线程是否为活动状态 42 System.out.println(thread.isAlive()); // true 43 // 4.3 判断线程是否为守护线程 44 System.out.println(thread.isDaemon()); // false 45 46 47 // 5. 停 48 // 5.1 让线程休眠指定毫秒数 49 new Thread(new Runnable() { 50 @Override 51 public void run() { 52 for (int i = 0; i < 50; i++) { 53 System.out.println(Thread.currentThread().getName() + "执行的第" + i + "次"); 54 if (i == 25) { 55 try { 56 /** 57 * 1. sleep()是静态方法 58 * 2. sleep()使用时必须捕获异常 59 * 3. sleep()执行时,只是让该线程进入阻塞状态,并不会释放锁 60 */ 61 System.out.println("线程2号正在休眠"); 62 Thread.sleep(5000); 63 } catch (InterruptedException e) { 64 e.printStackTrace(); 65 } 66 } 67 } 68 } 69 },"线程2号").start(); 70 71 // 5.2 暂停当前线程去执行其他线程 72 new Thread(new Runnable() { 73 @Override 74 public void run() { 75 for (int i = 0; i < 50; i++) { 76 System.out.println(Thread.currentThread().getName() + "执行了" + i + "次"); 77 if (i == 25) { 78 /** 79 * 1. yield()是静态方法 80 * 2. yield()执行时,让线程进入就绪状态,重新争抢CPU执行权,并不会释放锁 81 */ 82 Thread.yield(); 83 } 84 } 85 } 86 },"线程3号").start(); 87 88 // 5.3 等待线程销毁 89 new Thread(new Runnable() { 90 @Override 91 public void run() { 92 for (int i = 0; i < 100; i++) { 93 if (i == 50) { 94 /** 95 * 1. join()是对象方法 96 * 2. join()使用时必须捕获异常 97 * 3. join()使用场景:一个执行完的线程需要另一个正在执行的线程的运行结果时 98 */ 99 System.out.println("线程1号正在销毁!!!!"); 100 try { 101 thread.join(); 102 } catch (InterruptedException e) { 103 e.printStackTrace(); 104 } 105 System.out.println("线程1号销毁成功!!!!"); 106 } 107 } 108 } 109 },"线程4号").start(); 110 111 } 112 }
四、线程同步
1 import java.util.concurrent.locks.Lock; 2 import java.util.concurrent.locks.ReentrantLock; 3 4 5 /** 6 * 1. 线程安全 7 * 1. 什么是线程安全:当多个线程同时操作同一共享数据时,导致共享数据出错 8 * 2. 怎样解决:使用线程同步技术 9 * 10 * 2. 线程同步:将多个线程的数据共享 11 * 12 * 3. 实现线程同步的方式 13 * 1. 同步代码块:有synchronized关键字修饰的语句块 14 * 1. 实例代码块:锁对象是this或者任意对象 15 * 2. 静态代码块:锁对象是当前类的字节码文件 16 * 17 * 2. 同步方法: 有synchronized关键字修饰的方法 18 * 1. 实例方法 19 * 2. 静态方法 20 * 21 * 3. 使用重入锁 22 * 1. 声明锁对象 23 * 2. 给共享数据上锁 24 * 3. 在finally中解锁 25 * 26 * 4. wait()和notify() 27 * wait(): 线程等待,释放锁 28 * notify(): 唤醒等待状态线程 29 */ 30 31 class Bank{ 32 // 实例账户 33 private Integer account1 = 100; 34 // 静态账户 35 private static Integer account2 = 100; 36 // 1. 声明锁对象 37 private Lock lock = new ReentrantLock(); 38 39 40 41 /** 42 * 1. 同步代码块 43 */ 44 // 存钱1 45 public void save1(Integer money) { 46 // 实例代码块 47 synchronized (this) { 48 account1 += money; 49 } 50 System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); 51 } 52 // 取钱1 53 public void draw1(Integer money) { 54 // 实例代码块 55 synchronized (this) { 56 if (account1 - money < 0) { 57 System.out.println("账户余额不足"); 58 return; 59 } 60 account1 -= money; 61 System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); 62 } 63 } 64 // 存钱2 65 public static void save2(Integer money) { 66 // 静态代码块 67 synchronized (Bank.class) { 68 account2 += money; 69 } 70 System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); 71 } 72 // 取钱2 73 public static void draw2(Integer money) { 74 // 静态代码块 75 synchronized (Bank.class) { 76 if (account2 - money < 0) { 77 System.out.println("余额不足"); 78 return; 79 } 80 account2 -= money; 81 System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); 82 } 83 } 84 85 /** 86 * 2. 同步方法 87 */ 88 // 2.1 实例方法 89 public synchronized void save3(Integer money) { 90 account1 += money; 91 System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); 92 } 93 public synchronized void draw3(Integer money) { 94 if (account1 - money < 0) { 95 System.out.println("余额不足"); 96 return; 97 } 98 account1 -= money; 99 System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); 100 } 101 102 // 2.2 静态方法 103 public synchronized static void save4(Integer money) { 104 account2 += money; 105 System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); 106 } 107 public synchronized static void draw4(Integer money) { 108 if (account2 - money < 0) { 109 System.out.println("余额不足"); 110 return; 111 } 112 account2 -= money; 113 System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); 114 } 115 116 117 /** 118 * 3. 重入锁 119 */ 120 public void save5(Integer money) { 121 // 2. 上锁 122 lock.lock(); 123 try { 124 account1 += money; 125 System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); 126 } finally { 127 // 3. 解锁 128 lock.unlock(); 129 } 130 } 131 public void draw5(Integer money) { 132 // 2. 上锁 133 lock.lock(); 134 try { 135 if (account1 - money < 0) { 136 System.out.println("余额不足"); 137 return; 138 } 139 account1 -= money; 140 System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); 141 } finally { 142 // 3. 解锁 143 lock.unlock(); 144 } 145 } 146 147 // 查看账户余额 148 public void show() { 149 System.out.println("实例账户余额" + account1); 150 System.out.println("静态账户余额" + account2); 151 } 152 153 } 154 155 class Demo implements Runnable{ 156 private static Bank bank = new Bank(); 157 @Override 158 public void run() { 159 /** 160 * 1. 测试同步代码块 161 */ 162 // 1.1 实例代码块 163 bank.save1(100); 164 bank.show(); 165 bank.draw1(20); 166 bank.show(); 167 168 // 1.2 静态代码块 169 Bank.save2(100); 170 bank.show(); 171 Bank.draw2(20); 172 bank.show(); 173 174 /** 175 * 2. 测试同步方法 176 */ 177 // 2.1 实例方法 178 bank.save3(100); 179 bank.show(); 180 bank.draw3(20); 181 bank.show(); 182 // 2.2 静态方法 183 Bank.save4(100); 184 bank.show(); 185 Bank.draw4(20); 186 bank.show(); 187 188 /** 189 * 3. 测试重入锁 190 */ 191 bank.save5(100); 192 bank.show(); 193 bank.draw5(20); 194 bank.show(); 195 } 196 } 197 198 public class TestSynchronized { 199 public static void main(String[] args) { 200 // 1. 测试同步实例代码块 201 new Thread(new Demo(),"线程1号").start(); 202 // 2. 测试同步静态代码块 203 new Thread(new Demo(),"线程2号").start(); 204 205 // 2. 测试同步方法 206 // 2.1 实例方法 207 new Thread(new Demo(),"线程3号").start(); 208 // 2.2 静态方法 209 new Thread(new Demo(),"线程4号").start(); 210 211 // 3. 测试冲入锁 212 new Thread(new Demo(),"线程5号").start(); 213 214 } 215 }
五、线程控制(线程状态转换图)
九:网络编程
一、简介
1. 概述
1. 计算机网络:多台算机之间实现信息传递和资源共享的的计算机系统
2. 网络编程:不同计算机之间使用网络进行数据交换
2. 三要素
1. IP:每个设备在网络中的唯一标识
2. 端口号:每个程序在设备上的唯一标识
3. 协议:在网络中进行数据交换要遵守的规则
3. UDP与TCP的区别
1. UDP:面向无连接,数据不可靠,速度快,适用于高速传输和对实时性要求较高
2. TCP:面向连接,数据可靠,速度略低,适用于可靠传输
二、操作
1. 常用方法
2. UDP传输代码实现
1 import java.io.IOException; 2 import java.net.DatagramPacket; 3 import java.net.DatagramSocket; 4 import java.net.SocketException; 5 6 /** 7 * 1. 服务器端实现步骤 8 * 1. 创建服务器对象 9 * 2. 将接受到的数据打包 10 * 3. 将数据包存储到服务器对象 11 * 4. 打印数据 12 * 5. 关闭流通道 13 * 14 * 2. 客户端步骤实现 15 * 1. 创建客户端对象 16 * 2. 将数据打包 17 * 3. 发送数据包 18 * 4. 关闭流通道 19 * 20 * @author 萌萌哥的春天 21 * 22 */ 23 24 25 /** 26 * 服务器端 27 */ 28 public class Server { 29 public static void main(String[] args) throws IOException { 30 // 1. 创建服务器对象 31 DatagramSocket ds = new DatagramSocket(9102); 32 33 // 2. 将接收到的数据打包 34 byte[] bytes = new byte[1024]; 35 DatagramPacket dp = new DatagramPacket(bytes, bytes.length); 36 37 // 3. 将数据包存入服务器对象 38 ds.receive(dp); 39 40 // 4. 打印数据 41 String IP = dp.getAddress().getHostAddress(); // IP地址 42 int port = dp.getPort(); 43 String data = new String(dp.getData(), 0, dp.getLength()); // 将字节数组转为字符串 44 System.out.println(IP+": --" + data + "--" + port + ":"); 45 46 // 5. 关闭流通道 47 ds.close(); 48 } 49 } 50 51 /** 52 * 客户端 53 */ 54 public class Client { 55 public static void main(String[] args) throws IOException { 56 // 1. 创建客户端对象 57 DatagramSocket ds = new DatagramSocket(); 58 59 // 2. 将数据打包 60 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 接受键盘输入 61 byte[] bytes = br.toString().getBytes(); // 将字符串转换为字节数组 62 DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9102); 63 64 // 3. 发送数据包 65 ds.send(dp); 66 67 // 4. 关闭流通道 68 ds.close(); 69 } 70 } 71 72 复制代码
3. TCP传输代码实现
1 import java.io.BufferedWriter; 2 import java.io.BufferedReader; 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.InputStreamReader; 9 import java.io.OutputStreamWriter; 10 import java.net.ServerSocket; 11 import java.net.Socket; 12 import java.net.UnknownHostException; 13 14 /** 15 * 1. 服务器端实现步骤 16 * 1. 创建服务器对象 17 * 2. 侦听客户端连接 18 * 3. 使用输入流读取客户端输入 19 * 4. 使用输出流写入文件 20 * 5. 使用输出流通知客户端 21 * 6. 关闭流通道 22 * 23 * 2. 客户端步骤实现 24 * 1. 创建客户端对象 25 * 2. 使用输出流发送数据到服务器 26 * 3. 使用输入流读取本地文件 27 * 4. 使用输入流接收服务器反馈并打印到控制台 28 * 5. 关闭流通道 29 * 30 * @author 萌萌哥的春天 31 * 32 */ 33 34 35 /** 36 * 服务器端 37 */ 38 public class Server { 39 private static ServerSocket server; 40 private static Socket socket; 41 private static InputStream in; 42 private static OutputStream out; 43 44 public static void main(String[] args) { 45 try { 46 // 1. 创建服务器对象 47 server = new ServerSocket(9102); 48 49 // 2. 侦听客户端连接 50 socket = server.accept(); 51 52 // 3. 使用输入流接收客户端输入 53 in = socket.getInputStream(); 54 55 // 4. 使用输出流写入文件 56 out = new FileOutputStream("D:/server.txt"); 57 byte[] bytes = new byte[1024]; 58 int len = 0; 59 while ((len = in.read(bytes)) != -1) { 60 out.write(bytes, 0, len); 61 out.flush(); 62 } 63 64 // 5. 使用输出流通知客户端 65 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 66 bw.write("文件上传成功"); 67 bw.flush(); 68 69 } catch (FileNotFoundException e) { 70 e.printStackTrace(); 71 } catch (IOException e) { 72 e.printStackTrace(); 73 } finally { 74 // 6. 关闭流通道 75 if (server != null) { 76 try { 77 server.close(); 78 } catch (IOException e) { 79 e.printStackTrace(); 80 } 81 } 82 if (socket != null) { 83 try { 84 socket.close(); 85 } catch (IOException e) { 86 e.printStackTrace(); 87 } 88 } 89 if (in != null) { 90 try { 91 in.close(); 92 } catch (IOException e) { 93 e.printStackTrace(); 94 } 95 } 96 if (out != null) { 97 try { 98 out.close(); 99 } catch (IOException e) { 100 e.printStackTrace(); 101 } 102 } 103 } 104 } 105 } 106 107 /** 108 * 客户端 109 */ 110 public class Client { 111 private static Socket socket; 112 private static InputStream in; 113 114 public static void main(String[] args) { 115 try { 116 // 1. 创建客户端对象 117 socket = new Socket("localhost", 9102); 118 119 // 2. 使用输入流发送数据到服务器 120 OutputStream out = socket.getOutputStream(); 121 122 // 3. 使用输入流读取本地文件 123 in = new FileInputStream("D:/client.txt"); 124 byte[] bytes = new byte[1024]; 125 int len = 0; 126 while ((len = in.read(bytes)) != -1) { 127 out.write(bytes, 0, len); 128 } 129 130 // 4. 通知服务器文件已上传 131 socket.shutdownOutput(); 132 133 // 5. 使用输出流接收服务器反馈 134 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); 135 System.out.println(br.readLine()); 136 137 } catch (UnknownHostException e) { 138 e.printStackTrace(); 139 } catch (FileNotFoundException e) { 140 e.printStackTrace(); 141 } catch (IOException e) { 142 e.printStackTrace(); 143 } finally { 144 // 6. 关闭流通道 145 if (socket != null) { 146 try { 147 socket.close(); 148 } catch (IOException e) { 149 e.printStackTrace(); 150 } 151 } 152 if (in != null) { 153 try { 154 in.close(); 155 } catch (IOException e) { 156 e.printStackTrace(); 157 } 158 } 159 } 160 } 161 }
十:反射
一、概述
1. 反射机制:动态获取类的信息和调用对象的方法的功能
2. 反射实现:获取每个类的字节码文件,也就是Class类对象
二、反射的方式
1 /** 2 * 反射的三种方式:推荐2和3 3 * 1. Object类的getClass()方法 4 * 2. 实体类.class 5 * 3. Class类的forName()方法 6 */ 7 8 9 public class TestReflect { 10 public static void main(String[] args) { 11 // 1. 方式一:getClass()方法 12 Worker worker = new Worker(); 13 Class<? extends Worker> class1 = worker.getClass(); 14 System.out.println(class1.getName()); // Worker 15 16 // 2. 方式二:实体类.class 17 Class<Worker> class2 = Worker.class; 18 System.out.println(class1 == class2); // true 19 20 // 3. 方式三:Class类的forName()方法 21 try { 22 Class<?> class3 = Class.forName("Worker"); 23 System.out.println(class2 == class3); // true 24 } catch (ClassNotFoundException e) { 25 e.printStackTrace(); 26 } 27 } 28 }
三、操作
1. 常用方法
2. 常用方法代码实现
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 5 class Worker { 6 // 私有属性 7 private Integer id; 8 private String name; 9 // 公共属性 10 Integer age; 11 12 public Worker() { 13 } 14 15 public Worker(String name) { 16 this.name = name; 17 } 18 19 protected Worker(Integer id, String name) { 20 this.id = id; 21 this.name = name; 22 } 23 24 private Worker(Integer id, String name, Integer age) { 25 this.id = id; 26 this.name = name; 27 this.age = age; 28 } 29 30 // 继承方法 31 @Override 32 public String toString() { 33 return "Worker [id=" + id + ", name=" + name + ", age=" + age + "]"; 34 } 35 36 // 私有方法 37 private void test() { 38 System.out.println("这是私有方法"); 39 } 40 41 } 42 43 public class TestReflect { 44 public static void main(String[] args) { 45 // 1. 创建Class对象 46 Class<Worker> class1 = Worker.class; 47 Class<String> class2 = String.class; 48 49 50 /** 51 * 2. 类相关操作 52 */ 53 54 // 2.1 获取完整性类名 55 System.out.println(class2.getName()); // java.lang.String 56 57 // 2.2 获取类名 58 System.out.println(class2.getSimpleName()); // String 59 60 // 2.3 获取此类的包名 61 System.out.println(class2.getPackage()); // package java.lang 62 63 // 2.4 获取当前类所继承父类的名字 64 System.out.println(class2.getSuperclass()); // class java.lang.Object 65 66 // 2.5获取当前类实现的接口 67 Class<?>[] interfaces = class2.getInterfaces(); 68 for (Class<?> class3 : interfaces) { 69 System.out.println(class3); 70 // interface java.io.Serializable 71 // interface java.lang.Comparable 72 // interface java.lang.CharSequence 73 } 74 75 76 /** 77 * 3. 类中属性相关操作 78 */ 79 80 // 3.1 获取指定属性 81 try { 82 Field declaredField = class1.getDeclaredField("name"); 83 System.out.println(declaredField); // private java.lang.String Worker.name 84 } catch (NoSuchFieldException e) { 85 e.printStackTrace(); 86 } catch (SecurityException e) { 87 e.printStackTrace(); 88 } 89 90 // 3.2 获取所有属性 91 Field[] declaredFields = class1.getDeclaredFields(); 92 for (Field field : declaredFields) { 93 System.out.println(field); 94 // private java.lang.Integer Worker.id 95 // private java.lang.String Worker.name 96 // java.lang.Integer Worker.age 97 } 98 99 100 /** 101 * 4. 类中构造方法相关操作 102 */ 103 104 // 4.1 获取参数列表匹配的构造方法 105 try { 106 Constructor<Worker> declaredConstructor = class1.getDeclaredConstructor(Integer.class, String.class, Integer.class); 107 System.out.println(declaredConstructor); // private Worker(java.lang.Integer,java.lang.String,java.lang.Integer) 108 System.out.println(class1.getDeclaredConstructor(String.class)); // public Worker(java.lang.String) 109 } catch (NoSuchMethodException e) { 110 e.printStackTrace(); 111 } catch (SecurityException e) { 112 e.printStackTrace(); 113 } 114 115 // 4.2 获取类中所有公共构造方法 116 Constructor<?>[] constructors = class1.getConstructors(); 117 for (Constructor<?> constructor : constructors) { 118 System.out.println(constructor); 119 // public Worker(java.lang.String) 120 // public Worker() 121 } 122 123 // 4.3 获取类中所有构造方法 124 Constructor<?>[] declaredConstructors = class1.getDeclaredConstructors(); 125 for (Constructor<?> constructor : declaredConstructors) { 126 System.out.println(constructor); 127 // private Worker(java.lang.Integer,java.lang.String,java.lang.Integer) 128 // protected Worker(java.lang.Integer,java.lang.String) 129 // public Worker(java.lang.String) 130 // public Worker() 131 } 132 133 /** 134 * 5. 类中方法相关操作 135 */ 136 137 // 5.1 获取方法名和参数列表都匹配的方法 138 try { 139 Method declaredMethod = class1.getDeclaredMethod("toString"); 140 System.out.println(declaredMethod); // public java.lang.String Worker.toString() 141 System.out.println(class1.getDeclaredMethod("test")); // //private void Worker.test() 142 } catch (NoSuchMethodException e) { 143 e.printStackTrace(); 144 } catch (SecurityException e) { 145 e.printStackTrace(); 146 } 147 148 // 5.2 获取类中所有公共方法 149 Method[] methods = class1.getMethods(); 150 for (Method method : methods) { 151 System.out.println(method); // 当前类方法和它所继承的类及其实现的接口中的所有公共方法 152 } 153 154 // 5.3 获取当前类中所有方法 155 Method[] declaredMethods = class1.getDeclaredMethods(); 156 for (Method method : declaredMethods) { 157 System.out.println(method); 158 // public java.lang.String Worker.toString() 159 // private void Worker.test() 160 } 161 162 } 163 } 164 165 复制代码
3. 核心操作代码实现
1 import java.lang.reflect.Field; 2 import java.lang.reflect.Method; 3 4 class Worker { 5 // 私有属性 6 private Integer id; 7 private String name; 8 // 公共属性 9 public Integer age; 10 11 public Worker() { 12 } 13 14 @Override 15 public String toString() { 16 return "Worker [id=" + id + ", name=" + name + ", age=" + age + "]"; 17 } 18 19 // 私有方法 20 private void test() { 21 System.out.println("这是私有方法"); 22 } 23 24 // 公共方法 25 public void show() { 26 System.out.println("这是公共方法"); 27 } 28 } 29 30 public class TestReflect { 31 public static void main(String[] args) throws Exception { 32 // 1. 创建Class对象 33 Class<?> class1 = Class.forName("Worker"); 34 35 // 2. 通过构造方法实例化类对象 36 Object obj = class1.getConstructor().newInstance(); 37 38 // 3. 给公共属性设置值 39 Field field1 = class1.getField("age"); 40 field1.set(obj, 18); 41 42 // 4. 给私有属性设置值 43 Field field = class1.getDeclaredField("name"); 44 field.setAccessible(true); // 解除私有限定 45 field.set(obj, "张三"); // 为Worker类中的name属性设置值 46 47 // 5. 调用公共成员方法 48 Method method1 = class1.getMethod("show"); 49 method1.invoke(obj); 50 51 // 6. 调用私有成员方法 52 Method method = class1.getDeclaredMethod("test"); 53 method.setAccessible(true); 54 method.invoke(obj); // 第一个参数是类对象,其余的为实参 55 System.out.println(obj); 56 } 57 }