java学习
一、前言
-
1、JRE和JDK
- JRE
- Java程序的运行环境,包含JVM(Java虚拟机)和运行时所需要的核心类库
- JDK
- Java程序开发工具包,包含JRE和开发人员使用的工具(编译工具:javac.exe 运行工具:java.exe)
- 编译java代码:javac xx.java
- 解释执行字节码:java xx
- Java程序开发工具包,包含JRE和开发人员使用的工具(编译工具:javac.exe 运行工具:java.exe)
- JRE
-
2、JDK的下载与安装
- 下载地址:https://www.oracle.com/java/technologies/downloads/
- 一路点击下一步安装,在弹出框中可以不选择安装jre,因为jdk本身自带jre
- 安装后关闭Java自动检查更新:
- 开始菜单 - Java - 检查更新 - 取消自动检查更新 - 不检查
- 配置环境变量
- 添加系统环境变量JAVA_HOME,指向JDK安装目录,比如:D:\Softwares\Java\jdk1.8.0_181
- 添加系统环境变量CLASSPATH,指定:【.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;】
- 编辑系统环境变量path,添加如下2项:
- %JAVA_HOME%\bin
- %JAVA_HOME%\jre\bin
-
3、IDEA下载与安装
- Java开发的集成环境
- 官方下载地址:https://www.jetbrains.com/idea/
- 配置日志、插件等目录
- 默认在 c 盘,建议配置到其它盘,减轻c盘压力
- 打开安装目录/bin目录下的文件idea.properties,将前面4条注释过的路径打开,然后进行配置,比如
# Uncomment this option if you want to customize a path to the settings directory. #--------------------------------------------------------------------- idea.config.path=E:/ProgramFiles/.IntelliJIdea/config #--------------------------------------------------------------------- # Uncomment this option if you want to customize a path to the caches directory. #--------------------------------------------------------------------- idea.system.path=E:/ProgramFiles/.IntelliJIdea/system #--------------------------------------------------------------------- # Uncomment this option if you want to customize a path to the user-installed plugins directory. #--------------------------------------------------------------------- idea.plugins.path=E:/ProgramFiles/.IntelliJIdea/plugins #--------------------------------------------------------------------- # Uncomment this option if you want to customize a path to the logs directory. #--------------------------------------------------------------------- idea.log.path=E:/ProgramFiles/.IntelliJIdea/log
- 常用快捷键
- alt + 回车:万能纠错 / 生成返回值变量
- shift + f6:重命名文件 / 变量(修改多个)
- ctrl + f / ctrl + shift +f:局部 / 全局搜索
- ctrl + r / ctrl + shift + r:局部 / 全局替换
- ctrl + shift + v:粘贴历史内容
- ctrl + d:代码行复制
- ctrl + shift + e / ctr + e:查看最近访问过的本地 / 全局文件
- ctrl + q:提示方法的参数及类型
- ctrl + shift + u:全大写 / 小写切换
- alt + shift + 上 / 下键:代码行整体上 / 下移
- ctrl + /:代码注释
- 选中多排 + tab:整体右移
- 选中多排 + shift + tab:整体左移
- ctrl + z:撤销
- ctrl + shift + z:反撤销
- shift + 回车:向下开始新的一行
- ctrl + alt + 回车:向上开始新的一行
- ctrl + alt + l:代码格式化
- ctr + alt + v:快速补全对象调用方法后的返回值及类型
-
4、设置cmd命令行默认编码为UTF-8
- 通过win+r打开开始菜单搜索框,输入regedit
- 依次找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor
- 然后在右边空白处右键新建,选择‘字符串值’,名称填写autorun
- 然后在autorun上右键-修改,在数值数据中输入‘chcp 65001’
-
5、windows terminal常用快捷键
- 新建选项卡
- ctr + shift + d
- 划分窗格
- alt + shift + ( d 或者 - 或者 +)
- 关闭窗格
- ctr + shift + w
- 切换窗格
- alt + 方向键
- 调整窗格大小
- alt + shift + 方向键
- 新建选项卡
二、类和对象
-
1、类
- 类是Java程序的基本组成单位,是对现实生活中一类具有共同属性和行为的事物的抽象,确定对象将会拥有的属性和行为
- 属性:在类中通过成员变量来体现
- 行为:在类中通过成员方法来体现
- 定义
public class 类名{ // 成员变量 变量1的数据类型 变量1; 变量2的数据类型 变量2; ... // 成员方法 方法1; 方法2; ... }
- 类是Java程序的基本组成单位,是对现实生活中一类具有共同属性和行为的事物的抽象,确定对象将会拥有的属性和行为
-
2、对象
- 创建对象
- 类名 对象名= new 类名();
- 使用对象
- 使用成员变量
- 对象名.变量名
- 使用成员方法
- 对象名.方法名()
- 使用成员变量
- 示例
public class PhoneDemo { public static void main(String[] args) { // 创建对象 Phone p = new Phone(); // 使用成员变量 System.out.println(p.brand); // 默认值 null System.out.println(p.price); // 默认值 0 // 修改成员变量 p.brand = "苹果"; p.price = 9999; System.out.println(p.brand); System.out.println(p.price); //使用成员方法 p.call(); p.sendMessage(); } } class Phone{ // 成员变量 String brand; int price; // 成员方法 public void call(){ System.out.println("打电话"); } public void sendMessage(){ System.out.println("发短信"); } }
- 创建对象
-
3、成员变量和局部变量
- 成员变量:类中方法外的变量
- 局部变量:方法中的变量
-
4、包
- 作用
- 区分相同名字的类
- 控制访问范围
- 当类很多时,便于管理
- 建包
- 实际上就是创建不同的文件夹 / 目录来保存类文件
- 打包
- package 包名;
- package的作用是声明当前类所在的包,需要放在最上面,一个类中只能有一个pakcage
- 导包
- import xxx;
- java.lang.*是基本包,默认引入,不要导入
- jar包
- 制作
- jar cvf xx.jar foo/ . 将foo目录下的所有文件打包成xx.jar
- 查看
- jar tf xx.jar
- 运行
- java -jar xx.jar
- 其它参数,可使用: jar --help 查看
- 制作
- 作用
-
5、this关键字
- this:代表本类对象的引用
- 用于解决方法中形参和成员变量同名问题
- 如果方法中形参和成员变量同名,不带this修饰的变量指向形参,使用this修饰的变量是成员变量
- 对于形参没有与成员变量同名的情况下,使用成员变量时可省略this修饰
- 方法被哪个对象调用,this就代表哪个对象
- 用法:
- this.成员变量:访问成员变量
- this(...) :访问本类构造方法
- this.成员方法(...):访问本类成员方法
-
6、super关键字
- super关键字的用法和this关键字相似
- super:代表父类存储空间的标识(可以理解为父类对象引用)
- 用法:
- super.成员变量:访问父类成员变量
- super(...):访问父类构造方法
- super.成员方法(...):访问父类成员方法
-
7、修饰符
- 分类
- 权限修饰符
- 状态修饰符
- 权限修饰符
- private:只能在本类中访问
- 没有修饰符(默认):本类 + 同包
- protected:本类 + 同包 + 子类
- public:本类 + 同包 + 子类 + 不同包
- 注意:只有默认修饰符和public能够修饰类
- 状态修饰符
- final(最终态)
- 被修饰的类,不能被继承(最终类)
- 被修饰的方法,不能被重写(最终方法)
- 被修饰的变量,不能被再次赋值(常量)
- 变量是基本类型:数据值不能发生改变
- 变量是引用类型:地址值不能发生改变,但是地址里面的内容可以改变
- static(静态)
- 静态成员变量:被类的所有对象共享,既可以通过对象名调用,也可以通过类名调用(推荐使用类名调用)
- 静态成员方法:只能访问静态成员
- 分类
-
8、封装
- 概述
- 是面向对象三大特征之一(封装、继承、多态)
- 原则
- 将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
- 成员变量使用private关键字修饰,提供对应的 get() 和 set() 方法
public class Student { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
- 好处
- 通过方法来控制成员变量的操作,提高了代码的安全性
- 把代码用方法进行封装,提高了代码的复用性
- 概述
-
9、构造方法(构造器)
- 概述
- 构造方法是一种特殊的方法,主要是完成对象数据的初始化
- 格式
public class 类名{ 修饰符 类名(参数){ // 构造方法内书写的内容 } }
- 注意事项
- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
- 如果定义了构造方法,系统不再提供默认的构造方法
- 如果自定义了带参构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法
- 建议:无论是否使用,都手动书写无参数构造方法
public class Student { private String name; private int age; // 无参数构造方法 public Student() { } // 有参数构造方法 public Student(String name, int age) { this.name = name; this.age = age; } }
- 概述
-
10、继承
- 概述
- 可以使得子类具有父类的属性和方法,还可以在子类中重新定义、追加方法和属性
- 格式
- class 子类名 extends 父类名{ }
-
父类:也被称为基类、超类
- 子类:也被称为派生类
-
- class 子类名 extends 父类名{ }
- 继承好处
- 提高代码复用性(多个类相同的成员可以放到哦同一个类中)
- 提高代码维护性(如果方法的代码需要修改,修改一处即可)
- 继承中变量访问特点
- 子类局部范围找
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑祖先的情况下)
public class Demo { public static void main(String[] args) { // 创建对象 Son s = new Son(); // 调用show()方法 s.show(); } } // 继承父类 class Son extends Father { public int age = 20; public String gender = "男"; // 重写show方法 public void show() { int age = 22; System.out.println("age = " + age); // 22 => 使用局部变量 System.out.println("gender = " + gender); // 男 => 使用成员变量 System.out.println("height = " + height); // 180 => 使用父类变量 System.out.println("weight = " + weight); // 报错 } } class Father { public int age = 45; public int height = 180; public void show() { System.out.println("age = " + age); } }
- 继承中构造方法访问特点
- 子类中所有的构造方法,默认都会访问父类中无参的构造方法
- 因为子类会继承父类中的数据,可能还会使用父类的数据。所以子类初始化之前,一定要先完成父类数据的初始化
- 每一个子类构造方法的第一条语句,默认都是:super()
- 如果父类中没有无参构造方法,如何继承?
- 在父类中提供一个无参构造方法(推荐)
- 在子类构造方法第一行,通过super关键字去显示调用父类的带参构造方法
- 子类中所有的构造方法,默认都会访问父类中无参的构造方法
- 继承中成员方法访问特点
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑祖先的情况下)
- 方法重写
- 概述
- 子类中出现了和父类一模一样的方法声明
- @Override
- 是一个注解(后面会学习到)
- 可以帮助我们检查重写方法的方法声明正确性
- 注意事项
- 私有方法不能被重写(私有成员方法子类无法继承)
- 子类方法访问权限不能更低(public > 默认 > 私有)
- 概述
- 继承注意事项:
- Java中类只支持单继承(extends后不能出现多个类)
- Java中类支持多层继承
- 概述
-
11、多态
- 概述
- 同一个对象,在不同时刻表现出来的不同形态
- 举例:猫
- 可以说猫是猫:猫 cat = new 猫();
- 也可以说猫是动物:动物 animal = new 猫();
- 这里猫在不同时刻表现出来的不同形态,就是多态
- 多态的前提和体现
- 有继承 / 实现关系
- 有方法重写
- 有父(类 / 接口)引用指向(子 / 实现)类对象
- 多态中成员访问特点
- 成员变量:编译看左边,执行看左边
- 成员方法:编译看左边,执行看右边
- 原因:
- 成员方法有重写,而成员变量没有
public class Demo { public static void main(String[] args) { // 有父类引用指向子类对象 Animal a = new Cat(); // 执行时看右边,调用cat的eat方法 a.eat(); // 执行时看左边,输出动物的category System.out.println(a.category); // 动物没有show方法,无法通过编译 // a.show(); } } // 猫继承动物类 class Cat extends Animal { public String category = "猫"; // 重写动物类eat()方法 @Override public void eat() { System.out.println("猫在吃东西"); } public void show(){ System.out.println("我是一只小花猫"); } } class Animal { public String category = "动物"; public void eat() { System.out.println("动物在吃东西"); } }
- 成员方法有重写,而成员变量没有
- 多态中的转型
- 向上转型
- 从子到父,父类引用指向子类对象
- 示例:Anima a = new Cat();
- 向下转型
- 父类引用转为子类对象
- 示例
Animal a = new Cat(); // 向下转型 Cat c = (Cat)a; // 接下来就可以调用Cat类中的特有方法 c.xxx();
- 示例
- 父类引用转为子类对象
- 向上转型
- 概述
三、抽象类
-
1、概述
- 在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,则该类必须被定义为抽象类
-
2、特点
- 抽象类和抽象方法,必须使用abstract关键字修饰
- 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
- 抽象类不能实例化
- 但是可以参照多态的方式,通过子类对象实例化,这叫抽象类多态
- 抽象类的子类,要么重写抽象类中的所有抽象方法,要么也是抽象类
public class Demo { public static void main(String[] args) { Animal a = new Cat(); a.eat(); a.sleep(); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫在吃东西"); } } // 抽象类 abstract class Animal { // 抽象方法 public abstract void eat(); public void sleep() { System.out.println("动物在睡觉"); } }
四、接口
-
1、概述
- 接口是一种公共的规范标准,只要符合规范标准,大家都可以通用
- Java中的接口更多的体现在对行为的抽象
-
2、接口的特点
- 接口用关键字interface修饰
- public interface 接口名{ };
- 类实现接口用implements表示
- public 类名 implements 接口名{ };
- 接口不能被实例化
- 但是可以参照多态的方式,通过实现类对象实例化,这叫接口多态
- 多态的形式:具体类多态、抽象类多态、接口多态
- 接口的实现类
- 要么重写接口中的所有抽象方法
- 要么是抽象类
public class Demo { public static void main(String[] args) { // 接口多态 Jumping j = new Cat(); j.jump(); } } // 类实现接口 class Cat implements Jumping{ @Override public void jump() { System.out.println("猫在跳跃"); } } // 定义接口 interface Jumping { public abstract void jump(); // 等同于 // void jump(); }
- 接口用关键字interface修饰
-
3、接口的成员特点
- 成员变量
- 只能是常量
- 默认修饰符:public static final
- 构造方法
- 接口没有构造方法,因为接口主要是对行为进行抽象的,没有具体存在
- 一个类如果没有父类,默认继承自Object类
- 成员方法
- 只能是抽象方法
- 默认修饰符:publict abstract
- 总结:只能是常量和抽象方法
- 成员变量
-
4、类和接口的关系
- 类和类的关系
- 继承关系,只能单继承,但是可以多层继承
- 类和接口的关系
- 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 接口和接口的关系
- 继承关系,可以单继承,也可以多继承
// 继承一个类的同时,实现多个接口 public class InterImpl extends Object implements Inter1, Inter2, Inter3{ } interface Inter1{ } interface Inter2{ } // 接口多继承 interface Inter3 extends Inter1, Inter2{ }
- 继承关系,可以单继承,也可以多继承
- 类和类的关系
五、内部类
-
1、内部类概述
- 内部类:就是在一个类中定义一个类
- 内部类定义格式:
public class 类名{ 修饰符 class 类名{ } }
- 内部类访问特点:
- 内部类可以直接访问外部类的成员,包括私有,同名的情况下,会就近使用内部类成员变量,如果要使用外部类成员变量,可以使用(外部类名.this.成员名)
- 外部类要访问内部类的成员,必须创建对象
public class Outer{ private int num = 30; public class Inner{ public void show(){ // 访问外部类的私有成员变量 System.out.println(num); } } public void method(){ // 外部类访问内部类,必须创建对象 Inner i = new Inner(); i.show(); } }
-
2、成员内部类
- 在类的成员位置
- 外界如何创建对象使用?
-
- 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
- 范例:Outer.Inner oi = new Outer().new Inner();
-
-
3、局部内部类
- 局部内部类是在方法中定义的类,外界无法直接使用,需要在方法内部创建对象并使用
- 该类可以访问方法内的局部变量,也可以直接访问外部类的成员(外部类名.this.成员名)
package com.java.app; public class Demo { public static void main(String[] args) { Outer o = new Outer(); o.method(); } } class Outer { private int num = 30; public void method() { int num = 40; class Inner { public void show() { // 访问外部类成员 System.out.println(Outer.this.num); // 30 // 访问局部变量 System.out.println(num); // 40 } } // 内部创建对象并使用 Inner i = new Inner(); i.show(); } }
-
4、匿名内部类
- 概述
- 是局部内部类的一种特殊形式
- 前提
- 存在一个类或者接口,这里的类可以是具体类,也可以是抽象类
- 格式
new 类名或者接口名(){ 重写方法; };
- 本质
- 是一个继承了该类或者实现了该接口的子类匿名对象
public class Demo { public static void main(String[] args) { // 实例化对象 Cat c = new Cat(); // 传入一个实现了Jumping接口的匿名对象 c.method(new Jumping() { @Override public void jump() { System.out.println("猫在跳跃"); } }); // 传入一个继承了Animal抽象类的匿名对象 c.method2(new Animal() { @Override public void eat() { System.out.println("猫在吃东西"); } }); } } // 定义一个猫类 class Cat{ public void method(Jumping j){ j.jump(); } public void method2(Animal a){ a.eat(); } } // 定义抽象类 abstract class Animal{ public abstract void eat(); } // 定义接口 interface Jumping{ void jump(); }
- 是一个继承了该类或者实现了该接口的子类匿名对象
- 概述
-
5、获取各内部类名称
- 对象.getClass().getName()
- 各内部类命名特点
- 匿名内部类:外部类名$数字
- 数字从1开始,比如第3个匿名内部类的名字:外部类名$3
- 成员内部类和局部内部类命名规则相同,但是成员内部类会先加载
- 在成员内部类和局部内部类名不重复的情况下,默认使用:外部类名$1内部类名
- 类名重复的情况下,会依次使用:外部类名$1重复类名(成员内部类),外部类名$2重复类名(局部内部类)
package com.java.app; public class Demo { public static void main(String[] args) { // 实例化对象 Cat c = new Cat(); // 传入一个实现了Jumping接口的匿名对象 c.method(new Jumping() { @Override public void jump() { System.out.println("猫在跳跃"); } }); // 获取匿名类的名字 Jumping j = new Jumping() { @Override public void jump() { System.out.println("跳跃~"); } }; System.out.println(j.getClass().getName()); // com.java.app.Demo$2,因为前面定义过1个匿名内部类,占用了Demo$1 // 定义2个成员内部类 class Inner{ } class Inner2{ } // 获取成员内部类的名字 System.out.println(new Inner().getClass().getName()); //com.java.app.Demo$1Inner System.out.println(new Inner2().getClass().getName()); //com.java.app.Demo$1Inner2 // 获取局部内部类的名字 Demo.test(); //com.java.app.Demo$2Inner Demo.test2(); //com.java.app.Demo$3Inner } public static void test() { // 局部内部类 class Inner { } // 获取局部内部类的名字 System.out.println(new Inner().getClass().getName()); } public static void test2() { // 局部内部类 class Inner { } // 获取局部内部类的名字 System.out.println(new Inner().getClass().getName()); } } // 定义一个猫类 class Cat{ public void method(Jumping j){ j.jump(); } } // 定义接口 interface Jumping{ void jump(); }
- 匿名内部类:外部类名$数字
六、枚举类
-
1、概述
- 枚举类是一种特殊的类,里面包含一组有限的只读对象,枚举是一组常量的集合
- 使用关键字 enum 替代 class,会变成final类,并且隐示继承 Enum类
- 枚举对象必须放在枚举类的第一行
- 有多个枚举对象,使用逗号间隔,最后以分号结尾
- 使用无参的构造器创建枚举对象,小括号可以省略
- 枚举对象可以有多个属性
-
2、枚举类常用方法
public class Demo { @SuppressWarnings("all") public static void main(String[] args) throws Exception { Season spring = Season.SPRING; System.out.println(spring); // Season{name='春天', desc='暖和'} // 枚举类.valueof():将字符串转换成枚举对象,字符串必须为已有枚举对象名 Season spring2 = Season.valueOf("SPRING"); System.out.println(spring == spring2); // true,枚举对象只实例化一次 // name():返回枚举对象的名字 System.out.println(spring.name()); // SPRING // ordinal():返回枚举对象的次序/编号,从0开始 System.out.println(spring.ordinal()); // 枚举类.values():返回定义的所有枚举类对象 for (Season season : Season.values()) { System.out.println("season = " + season.name); } Season autumn = Season.AUTUMN; // compareTo():返回枚举对象的相对位置(即各自的次序相减) System.out.println(spring.compareTo(autumn)); // 1 - 3 = -2 } } enum Season{ // 枚举对象放在首行,多个枚举对象使用逗号分隔,以分号结尾 SPRING("春天", "暖和"), SUMMER("夏天", "炎热"), AUTUMN("秋天", "凉爽"), WINTER("冬天", "寒冷"); public String name; public String desc; Season() { } Season(String name, String desc) { this.name = name; this.desc = desc; } @Override public String toString() { return "Season{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}'; } }
七、数组
-
1、定义
- 数组(Array)是一种用于存储多个相同类型数据的存储模型
- 格式
- 数据类型[ ] 变量名 => int[ ] arr
- 定义了一个int类型的数组,数组名是arr
-
2、初始化方式
- 动态初始化
- 初始化时只指定数组长度,由系统为数组分配初始值
- 格式
- 数据类型[ ] 变量名 = new 数据类型[数组长度]
- 范例: int[ ] arr = new int[3];
- 静态初始化
- 初始化时指定每个元素的初始值,由系统决定数组长度
- 格式
- 数据类型[ ] 变量名 = new 数据类型[ ] {数据1, 数据2, 数据3, ...}
- 范例: int[ ] arr = new int[ ]{1, 2, 3};
- 简化格式
- 数据类型[ ] 变量名 = {数据1, 数据2, 数据3, ...}
- 范例:int[ ] arr = {1, 2, 3};
- 动态初始化
-
3、常见操作
- 遍历
// 定义数组 int[] arr = {11, 22, 33, 44, 55}; // 通用格式遍历 for (int index = 0; index < arr.length; index++) { // arr.length 表示数组的长度 System.out.println(arr[index]); // 通过索引获取数组中的元素,索引从0开始 }
- 获取最值
// 定义数组 int[] arr = {35, 22, 41, 17, 26, 77, 49}; // 定义变量,用于保存最大值,默认数组中的第一个值 int max = arr[0]; // 遍历数组,与数组中的其它元素挨个比较,将最大值保存到max变量中 for (int index = 1; index < arr.length; index++) { if(arr[index] > max){ max = arr[index]; } }
- 遍历
八、Arrays
-
1、概述
- Arrays类包含用于操作数组的各种方法
-
2、常用方法
- Arrays.toString(int[] a):返回指定数组内容的字符串表示形式
- Arrays.sort(int[] a):按照数字顺序排列指定数组
-
3、工具类的设计思想
- 构造方法使用private修饰
- 成员用public static修饰
九、String
-
1、概述
- String类代表字符串,Java程序中所有的双引号字符串都是String类的对象
- 字符串不可变,但是可以被共享
-
2、构造方法
- 示例
// 1、创建一个空白字符串对象,不含有任何内容 String s1 = new String(); System.out.println("s1 = " + s1); // 2、根据字符数组的内容,来创建字符串对象 String s2 = new String(new char[] {'a', 'b', 'c'}); System.out.println("s2 = " + s2); // 3、根据字节数组的内容,来创建字符串对象 String s3 = new String(new byte[] {97, 98, 99}); System.out.println("s3 = " + s3); // 4、直接赋值 String s4 = "abc"; System.out.println("s4 = " + s4);
- 示例
-
3、String对象特点
- 通过new关键字创建的字符串对象,每次new都会申请一个内存空间,即地址值不同
- 通过直接赋值("xxx")形式给出的字符串,只要序列相同,JVM都只会建立一个String对象,并在字符串池中维护
-
4、字符串比较
- 比较地址值:==
- 基本类型:比较的是数据值
- 引用类型:比较的是地址值
- 比较内容:对象.equals()
- 将此字符串与指定对象进行比较,比较的是内容
- 示例
// 1、通过构造方法的形式得到对象 String s1 = new String(new char[] {'a', 'b', 'c'}); String s2 = new String(new char[] {'a', 'b', 'c'});// 2、通过直接赋值的方式得到对象 String s3 = "abc"; String s4 = "abc"; // 3、比较地址值 System.out.println(s1 == s2); // false => new出来的对象,拥有不同的地址值 System.out.println(s3 == s4); // true => 直接赋值,只会建立一个对象 // 4、比较内容 System.out.println(s1.equals(s2)); // true => 比较的是内容 System.out.println(s3.equals(s4)); // true => 比较的是内容
- 比较地址值:==
-
5、常见操作
- 遍历
// 1、键盘录入字符串 Scanner scanner = new Scanner(System.in); System.out.println("请输入字符串:"); String s = scanner.nextLine(); // 2、遍历字符串 // 2.1 通过length()方法,获取字符串长度 // 2.2 通过charAt(index)方法,获取指定索引字符 for (int index = 0; index < s.length(); index++) { System.out.println(s.charAt(index)); }
- 遍历
十、StringBuilder
-
1、概述
- 如果对字符串进行拼接操作,每次拼接都会构建一个新的String对象,既耗时,又浪费内存空间
- StringBuilder是一个内容可变的字符串类,而String内容不可变
-
2、构造方法
// 1、创建一个空白可变字符串对象 StringBuilder sb = new StringBuilder(); System.out.println("sb = " + sb); System.out.println(sb.length()); // 2、根据字符串内容,来创建可变字符串对象 StringBuilder sb2 = new StringBuilder("hello world!"); System.out.println("sb2 = " + sb2); System.out.println(sb2.length());
-
3、添加和反转方法
- append(任意类型):添加对象,并返回对象本身
- reverse:返回相反的字符序列
// 1、创建一个空白可变字符串对象 StringBuilder sb = new StringBuilder(); // 2、append(任意类型):添加数据,并返回对象本身 sb.append("hello").append("world").append(100); // 链式编程 System.out.println("sb = " + sb); // 3、reverse():反转字符串 sb.reverse(); System.out.println("sb = " + sb);
-
4、StringBuilder和String相互转换
- StringBuilder转String:调用StringBuilder对象的toString()方法
- String转StringBuilder:通过StringBuilder的构造方法,传入String对象作为参数
// 1、创建一个空白可变字符串对象 StringBuilder sb1 = new StringBuilder(); sb1.append("hello world"); // 2、StringBuilder转String String s1 = sb1.toString(); System.out.println("s1 = " + s1); // 3、定义一个String字符串 String s2 = "hello"; // 4、String转StringBuilder StringBuilder sb2 = new StringBuilder(s2); System.out.println("s2 = " + s2);
十一、Integer
-
1、静态方法获取对象
- Integer.valueOf(int i):返回表示指定的 int 值的 Integer 实例
- Integer.valueOf(String s):返回一个保存指定值的 Integer 对象 String
-
2、int 和 String 的相互转换
- int 转 String
- String.valueOf(int i)
- String 转 int
- Integer.parseInt(String s)
- int 转 String
-
3、随机值
import java.math.BigInteger; import java.security.SecureRandom; public class Hello { public static void main(String[] args) { // 随机生成80位,10个字节 BigInteger v4 = new BigInteger(80, new SecureRandom()); // 让字节以16进制展示 String res = v4.toString(16); System.out.println(res); } }
注意:1个字节=8比特位,所以需要进行转换
十二、异常
-
1、概述
- 异常:就是程序出现了不正常的情况
-
2、异常处理
- try...catch...
- 格式
try{ 可能出现异常的代码; }catch{ 异常的处理代码; }
- 格式
- throws
- 格式
throws 异常类名;
注意:格式是跟在方法括号后面
- 格式
- try...catch...
-
3、自定义异常
- 格式
public class 异常类名 extends Exception{ 无参构造 带参构造 }
- 范例
import java.util.Scanner; public class Demo { public static void main(String[] args) { // 实例化对象 Teacher t = new Teacher(); Scanner scanner = new Scanner(System.in); System.out.println("请输入分数:"); int score = scanner.nextInt(); try { t.checkScore(score); } catch (ScoreException e) { e.printStackTrace(); // 把异常的错误信息输出在控制台 } } } class Teacher { public void checkScore(int score) throws ScoreException { if (score < 0 || score > 100) { // 抛出自定义异常 throw new ScoreException("分数异常!"); } else { System.out.println("分数正常!"); } } } // 自定义异常 class ScoreException extends Exception { // 无参构造 public ScoreException() { } // 带参构造 public ScoreException(String message) { super(message); } }
- 格式
-
4、throws 和 throw 的区别
- thorws
- 用在方法声明后面,跟的是异常类名
- 表示抛出异常,由该方法的调用者来处理
- 表示出现异常的一种可能性,并不一定会发生这些异常
- throw
- 用在方法体内,跟的是异常对象名
- 表示抛出异常,由方法体内的语句处理
- 执行 throw 一定抛出了某种异常
- thorws
十三、集合
-
1、概述
- 集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以发生改变
-
2、集合体系结构
-
- 集合
- Collection(单列)
- List(可重复)
- ArrayList(红色背景的表示实现类,其余均是接口,下同)
- LinkedList
- ...
- Set(不可重复)
- HashSet
- TreeSet
- ...
- List(可重复)
- Map(双列)
- HashMap
- ...
- Collection(单列)
- 集合
-
-
3、Collection集合
- Collection集合概述
- 是单列集合的顶层接口,它表示一组对象,这些对象也被称为Collection的元素
- JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
- 创建Collection集合的对象
- 多态的方式
- 比如:Collection<String> c = new ArrayList<String>();
- 多态的方式
- Collection集合常用方法
- add(E e):添加元素
- remove(Object o):从集合中移除指定的元素
- clear():清空集合中的元素
- contains(Objecto):判断集合中是否存在指定的元素
- isEmpty():判断集合是否为空
- size():集合的长度,也就是集合中元素的个数
- Collection集合的遍历
- iterator:迭代器,集合的专用遍历方式
- iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
- 迭代器是通过集合的iterator()方法得到的,依赖于集合而存在
- iterator的常用方法:
- next():返回迭代中的下一个元素
- hasNext():如果迭代具有更多元素,则返回true
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Demo { public static void main(String[] args) { // 创建集合对象 Collection<String> c = new ArrayList<String>(); // 添加元素 c.add("hello"); c.add("world"); c.add("java"); // 通过集合的iterator()方法,获取该集合中元素的迭代器 Iterator<String> it = c.iterator(); // while循环遍历 while (it.hasNext()) { String s = it.next(); System.out.println("s = " + s); } } }
- iterator:迭代器,集合的专用遍历方式
- Collection集合概述
-
4、List集合
- 概述
- 有序集合(序列),用户可以精确控制列表中每个元素的插入位置,可以通过证书索引访问元素,并搜索元素
- 与Set集合不同,List集合通常允许重复的元素
- List集合特点
- 有序:存储和取出的元素顺序一致
- 可重复:存储的元素可以重复
- List集合特有方法
- add(int index, E element):在集合中的指定位置插入指定的元素
- remove(int index):删除指定索引处的元素,返回被删除的元素
- set(int index, E element):修改指定索引处的元素,返回被修改的元素
- get(int index):返回指定索引处的元素
- 并发修改异常
- 产生原因:迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致
- 解决方案:用 for 循环,然后用集合对象做对应的操作
- ListIterator
- 列表迭代器
- 通过List集合的listIterator()方法得到,是List集合特有的迭代器
- 运行沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
- ListIterator中的常用方法
- next():返回迭代中的下一个元素
- hasNext():如果迭代具有更多元素,则返回true
- previous():返回列表中的上一个元素
- hasPrevious():如果列表迭代器相反方向遍历时具有更多元素,则返回true
- add(E e):将指定的元素插入列表
- 列表迭代器
- 增强 for 循环
- 概述:
- 简化数组和Collection集合的遍历
- 实现Iterable接口的类允许其对象成为增强 for 循环语句的目标
- JDK5以后出现的,内部原理是一个Iterator迭代器
- 格式:
for(元素数据类型 变量名: 数组或者Collection集合) { // 此处使用变量即可,该变量就是元素 }
- 概述:
- List集合子类特点
- List集合常用子类:
- ArrayList:底层数据结构是数组,查询块,增删慢
- 常用方法
- add(E e):在集合末尾添加指定元素
- add(int index, E element):在集合的指定位置插入指定元素
- remove(Object o):删除指定的元素,没有则不删除
- remove(int index):删除指定索引处的元素
- set(int index, E element):修改指定索引处的元素
- get(int index):获取指定索引处的元素
- size():获取集合中的元素个数
// 1、创建ArrayList集合对象 ArrayList<String> arr = new ArrayList<String>(); // 2、集合末尾添加元素 arr.add("hello"); arr.add("world"); arr.add("wow"); System.out.println(arr); // [hello, world, wow] // 3、集合指定位置添加元素 arr.add(1,"java"); System.out.println(arr); // [hello, java, world, wow] // 4、获取指定位置元素 System.out.println(arr.get(1)); // java // 5、删除指定元素 arr.remove("wow"); System.out.println(arr); // [hello, java, world] // 6、删除指定位置元素 arr.remove(1); System.out.println(arr); // [hello, world] // 7、获取集合中元素个数 System.out.println(arr.size()); // 2
- ArrayLis集合遍历(3种方式)
import java.util.ArrayList; import java.util.Iterator; public class Demo { public static void main(String[] args) { // 创建对象 ArrayList<String> arr = new ArrayList<String>(); // 添加元素 arr.add("hello"); arr.add("world"); arr.add("java"); // 遍历方式一:迭代器 Iterator<String> it = arr.iterator(); while (it.hasNext()) { String s = it.next(); System.out.println("s = " + s); } System.out.println("--------"); // 遍历方式二:普通for循环 for (int i = 0; i < arr.size(); i++) { String s = arr.get(i); System.out.println("s = " + s); } System.out.println("--------"); // 遍历方式三:增强for循环 for (String s : arr) { System.out.println("s = " + s); } } }
- 常用方法
- LinkedList:底层数据结构是链表,查询慢,增删快
- LinkedList集合特有方法
- addFirst(E e):在该列表开头插入指定的元素
- addLast(E e):将指定的元素追加到此列表末尾
- getFirst():返回此列表中的第一个元素
- getLast():返回此列表中的最后一个元素
- removeFirst():从此列表中删除并返回第一个元素
- removeLast():从此列表中删除并返回最后一个元素
- LinkedList集合特有方法
- ArrayList:底层数据结构是数组,查询块,增删慢
- List集合常用子类:
- 概述
-
5、Set集合
- Set集合特点
- 不包含重复元素的集合
- 没有带索引的方法,所以不能使用普通 for 循环
import java.util.HashSet; import java.util.Set; public class Demo { @SuppressWarnings("all") public static void main(String[] args){ // 创建集合对象 Set<String> s = new HashSet<String>(); // 添加元素 s.add("hello"); s.add("world"); s.add("java"); // 不包含重复元素 s.add("world"); // HashSet集合对迭代的顺序不作任何保证 for (String s1 : s) { System.out.println("s1 = " + s1); } } }
- 哈希值
- 哈希值:是 JDK 根据对象的地址或者字符串或者数字算出来的 int 类型的数值
- Object 类中有一个方法可以获取对象的哈希值
- hashCode():返回对象的哈希值
- 对象的哈希值特点:
- 同一个对象多次调用hashCode()方法,返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现不同对象的哈希值相同
- HashSet集合
- HashSet集合特点
- 底层数据结构是哈希表
- 对集合的迭代顺序不作任何保证
- 没有带索引的方法,不能使用普通 for 循环
- 不包含重复元素
- 如何保证对象的成员变量值相同,就认为是同一个对象?
- 重写hashCode() 和 equals() 方法---(自动生成即可)
- HashSet集合特点
- LinkedHashSet集合
- LinkedHashSet集合特点
- 由哈希表和链表实现的Set接口,具有可预测的迭代顺序
- 由链表保证元素有序
- 由哈希表保证元素唯一
- LinkedHashSet集合特点
- TreeSet集合
- TreeSet集合特点
- 元素有序(按照一定的规则,具体排序方式取决于构造方法)
- TreeSet():根据元素的自然排序进行排序
- TreeSet(Comparator comparator):根据指定的比较器进行排序
- 没有带索引的方法,不能使用普通 for 循环
- 不包含重复元素
- 元素有序(按照一定的规则,具体排序方式取决于构造方法)
- 自然排序 Comparable 的使用
- 自然排序,就是让元素所属的类实现 Comparable 接口,重写 compareTo(T o)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
import java.util.TreeSet; public class Demo { @SuppressWarnings("all") public static void main(String[] args) { // 创建集合对象 TreeSet<Student> s = new TreeSet<Student>(); // 添加元素 s.add(new Student("wangzhaojun", 25)); s.add(new Student("diaochan", 29)); s.add(new Student("xishi", 27)); s.add(new Student("yangyuhuan", 21)); // 不包含重复元素 s.add(new Student("diaochan", 29)); // 遍历集合 for (Student stu : s) { System.out.println(stu.name + "," + stu.age); } } } class Student implements Comparable<Student> { public String name; public int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public int compareTo(Student o) { // 按照年龄从小到大排序,如果需要从大到小排序,this 和 o 交换位置即可 int num = this.age - o.age; // 年龄相同,按照姓名字母顺序排序(String已经实现了compareTo接口) int num2 = num == 0 ? this.name.compareTo(o.name) : num; return num2; } }
- 比较器排序 Comparator 的使用
- TreeSet集合存储自定义对象,带参构造方法使用比较器排序对元素进行排序
- 比较器排序,就是让集合构造方法接收 Comparator 的实现类对象,重写 compare(T o1, T o2)方法
- 重写方法时,一定要注意排序规则:先主要条件,再次要条件
import java.util.Comparator; import java.util.TreeSet; public class Demo { @SuppressWarnings("all") public static void main(String[] args) { // 创建集合对象(通过匿名内部类的形式传入比较器对象) TreeSet<Student> s = new TreeSet<Student>(new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { // 按照年龄从小到大排序,如果需要从大到小排序,s1 和 s2 交换位置即可 int num = s1.age - s2.age; // 年龄相同,按照姓名字母顺序排序 int num2 = num == 0 ? s1.name.compareTo(s2.name) : num; return num2; } }); // 添加元素 s.add(new Student("wangzhaojun", 25)); s.add(new Student("diaochan", 29)); s.add(new Student("xishi", 27)); s.add(new Student("ruhua", 27)); s.add(new Student("yangyuhuan", 21)); // 不包含重复元素 s.add(new Student("diaochan", 29)); // 遍历集合 for (Student stu : s) { System.out.println(stu.name + "," + stu.age); } } } class Student { public String name; public int age; public Student(String name, int age) { this.name = name; this.age = age; } }
- TreeSet集合特点
- Set集合特点
-
6、泛型
- 概述
- 本质是参数化类型,也就是说操作的数据类型被指定为一个参数
- 将类型由原来的具体的类型参数化,然后在使用 / 调用时传入具体的类型
- 这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
- 泛型定义格式
- <类型>:指定一种类型的格式。这里的类型可以看成是形参,具体调用时,只能是引用数据类型
- <类型1, 类型2...>:指定多种类型的格式,多种类型之间用逗号隔开
- 泛型的好处:
- 把运行时期的问题提前到了编译期间
- 避免了强制类型转换
- 泛型类、方法、接口
- 泛型类:
- 定义格式:修饰符 class 类名<类型>{ };
- 范例:public class Generic<T>{ }
- 常见的如T、E、K、V等形式的参数常用于表示泛型
- 泛型方法:
- 定义格式:修饰符 <类型> 返回值类型 方法名(类型 变量名){ }
- 范例:public <T> void show(T t){ }
- 泛型接口
- 定义格式:修饰符 interface 接口名<类型>{ }
- 范例:public interface Generic<T>{ }
- 泛型接口实现类定义格式:修饰符 class 类名<类型> implements 接口名<类型>{ }
- 泛型接口实现类范例:public class GenericImpl<T> implements Generic<T>{ }
- 示例
public class Demo { @SuppressWarnings("all") public static void main(String[] args) { // 泛型类测试 Generic<String> g1 = new Generic<String>(); g1.show("100"); Generic<Integer> g2 = new Generic<Integer>(); g2.show(100); Generic<Boolean> g3 = new Generic<Boolean>(); g3.show(true); // 泛型方法测试 Generic2 gg1 = new Generic2(); gg1.show("100"); gg1.show(100); gg1.show(true); // 泛型接口测试 GenericImpl<String> ggg1 = new GenericImpl<String>(); ggg1.show("100"); GenericImpl<Integer> ggg2 = new GenericImpl<Integer>(); ggg2.show(100); GenericImpl<Boolean> ggg3 = new GenericImpl<Boolean>(); ggg3.show(true); } } // 泛型类 class Generic<T>{ public void show(T t){ System.out.println("t = " + t); }; } // 泛型方法 class Generic2{ public <T> void show(T tt){ System.out.println("tt = " + tt); } } // 泛型接口 interface Generic3<T>{ void show(T t); } // 泛型接口实现类 class GenericImpl<T> implements Generic3<T>{ @Override public void show(T ttt) { System.out.println("ttt = " + ttt); } }
- 泛型类:
- 类型通配符
- 任意类型通配符:<?>
- List<?>:元素类型未知的List
- 示例:List<?> list = new ArrayList<Object>()
- 类型通配符上限:<? extends 类型>
- List<? extends Number>:Number或者其子类型
- 示例:List<? extends Number> list = new ArrayList<Integer>()
- 类型通配符下限:<? super 类型>
- List<? super Number>:Number或者其父类型
- 示例:List<? super Number> list = new ArrayList<Object>()
- 任意类型通配符:<?>
- 可变参数
- 格式:修饰符 返回值类型 方法名(数据类型... 变量名)
- 范例:public static int sum(int... a){ }
- 注意事项:
- 这里的变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
- 概述
-
7、Map集合
- 概述
- interface Map<K, V> K:键的类型,V:值的类型
- 将键映射到值的对象;不能包含重复的键;每个键映射到最多一个值
- 创建Map集合的对象
- 多态的方式
- 具体的实现类 HashMap
- Map集合常用方法:
- V put(K key, V value):添加元素
- V get(Object key):根据键获取值
- Set<K> keySet():获取所有键的集合
- Collection<V> values():获取所有值的集合
- V remove(Object key):根据键删除键值对元素
- Set<Map.Entry<K, V>> entrySet():获取所有键值对对象的集合
- void clear():移除所有的键值对元素
- boolean containsKey(Object key):判断集合是否包含指定的键
- boolean containsValue(Object value):判断集合是否包含指定的值
- boolean isEmpty():判断集合是否为空
- int size():集合的长度,也就是集合中键值对的个数
- Map集合的遍历
- 方式一:先获取所有键的集合,然后根据键,获取相应值
-
方式二:先获取所有键值对对象的集合,然后根据单个对象获取其键、值
import java.util.HashMap; import java.util.Map; import java.util.Set; public class Demo { @SuppressWarnings("all") public static void main(String[] args) { // 创建Map集合对象 Map<String, String> m = new HashMap<String, String>(); // 添加元素 m.put("林青霞", "北京"); m.put("王祖贤", "上海"); m.put("张曼玉", "重庆"); m.put("周慧敏", "天津"); m.put("小龙女", "成都"); m.put("小辣椒", "武汉"); // 判断集合是否为空 System.out.println(m.isEmpty()); // 输出集合 System.out.println("m = " + m); // 输出集合大小 System.out.println(m.size()); // 根据键获取值 System.out.println(m.get("林青霞")); // 判断键是否存在 System.out.println(m.containsKey("小龙女")); System.out.println(m.containsKey("如花")); // 判断值是否存在 System.out.println(m.containsValue("武汉")); System.out.println(m.containsValue("大连")); // 获取所有键的集合 System.out.println(m.keySet()); // 获取所有值的集合 System.out.println(m.values()); // 遍历方式一: // 先获取所有键的集合,遍历键,获取相应值 Set<String> keySet = m.keySet(); // 遍历键的集合 for (String s : keySet) { // 根据键,获取相应的值 String v = m.get(s); System.out.println(s + "," + v); } // 遍历方式二: // 先获取所有键值对对象的集合,然后遍历该集合,然后根据对象,通过getKey()和getValue()方法获取每个对象的键和值 Set<Map.Entry<String, String>> entries = m.entrySet(); // 遍历键值对对象集合 for (Map.Entry<String, String> entry : entries) { // 获取单个对象的键 String k = entry.getKey(); // 获取单个对象的值 String v = entry.getValue(); System.out.println(k + "," + v); } } }
- 概述
-
8、Collections
- 概述
- 针对集合操作类的工具类
- Collections类的常用方法
- public static <T extends Comparable<? super T>> void sort(List<T> list):将指定的列表按升序排序
- public static void reverse(List<?> list):反转指定列表中元素的顺序
- public static void shuffle(List<?> list):使用默认的随机源随机排列指定的列表
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Demo { @SuppressWarnings("all") public static void main(String[] args) { // 创建列表对象 List<Integer> list = new ArrayList<Integer>(); //向列表中添加元素 list.add(30); list.add(20); list.add(50); list.add(10); list.add(40); // 升序排序 Collections.sort(list); System.out.println(list); // 反转 Collections.reverse(list); System.out.println(list); // 随机排 Collections.shuffle(list); System.out.println(list); } }
- 概述
十四、反射
-
1、概述
- Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。这种动态性,极大的增强程序的灵活性,不用在编译期就完成确定,在运行期仍然可以扩展
-
2、获取 Class 类的对象
- 如果想通过反射去使用一个类,首先要获取到该类的字节码文件对象,也就是类型为Class 类型的对象
- 三种方式:
- 使用类的 class 属性
- 基本数据类型,也可以通过.class属性得到对应的Class对象,比如int.class
- 示例:Student.class 会返回Student 类对应的 Class对象
- 调用对象的getClass()方法
- Object 类中的方法,所有对象都可以调用
- 使用Class类中的静态方法forName(String className),需要传入类的全路径(含完整包名)
- 使用类的 class 属性
-
3、反射获取构造方法并使用
- Class类中用于获取构造方法对象的方法
- Constructor<?>[] getConstructors():返回所有公有构造方法的数组
- Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公有构造方法对象,参数为数据类型对应的字节码文件对象(比如:int.class)
- Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
- Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象
- Constructor类中用于创建对象的方法
- T newInstance(Object... initargs):根据指定的构造方法创建对象
- public void setAccessible(boolean flag):值为true,取消访问检查(暴力反射,可以访问私有构造方法)
package com.java.app; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Demo { @SuppressWarnings("all") public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { // 获取Class对象 Class<?> c = Class.forName("com.java.app.Student"); // 获取并遍历所有公有构造方法的数组 Constructor<?>[] constructors = c.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } System.out.println("------------"); // 获取并遍历所有构造方法的数组 Constructor<?>[] declaredConstructors = c.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } System.out.println("------------"); // 获取单个公有构造方法对象 Constructor<?> constructor = c.getConstructor(); // 通过无参构造方法创建对象 Object o = constructor.newInstance(); System.out.println(o); System.out.println("------------"); // 获取带3个参数的构造方法 Constructor<?> declaredConstructor2 = c.getDeclaredConstructor(String.class, String.class, int.class); // 暴力反射 declaredConstructor2.setAccessible(true);// 值为true,取消访问检查 // 通过带参构造方法创建对象 Object o2 = declaredConstructor2.newInstance("张曼玉", "女", 30); System.out.println(o2); } } class Student { private String name; String gender; public int age; public Student() { } Student(String name, String gender) { this.name = name; this.gender = gender; } private Student(String name, String gender, int age) { this.name = name; this.gender = gender; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", gender='" + gender + '\'' + ", age=" + age + '}'; } }
- Class类中用于获取构造方法对象的方法
-
4、反射获取成员变量并使用
- Class 类中获取成员变量的方法
- Field[] getFields():返回所有公有成员变量对象的数组
- Field[] getField(String name):返回单个公有成员变量对象
- Field[] getDeclaredFields():返回所有成员变量的数组
- Field[] getDeclaredField(String name):返回单个成员变量对象
- Field 类中用于给成员变量赋值的方法
- Void set(Object obj, Object value):给obj对象的成员变量赋值value
package com.java.app; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; public class Demo { @SuppressWarnings("all") public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException { // 获取Class对象 Class<?> c = Class.forName("com.java.app.Student"); // 获取Field对象 Field name = c.getDeclaredField("name"); name.setAccessible(true); Field age = c.getDeclaredField("age"); age.setAccessible(true); // 获取无参构造器对象 Constructor<?> declaredConstructor = c.getDeclaredConstructor(); Object o = declaredConstructor.newInstance(); // 设置属性值 name.set(o, "张曼玉"); age.set(o, 30); // 读取属性值 System.out.println(name.get(o)); System.out.println(age.get(o)); System.out.println(o); } } class Student { private String name; String gender; public int age; public Student() { } Student(String name, String gender) { this.name = name; this.gender = gender; } private Student(String name, String gender, int age) { this.name = name; this.gender = gender; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", gender='" + gender + '\'' + ", age=" + age + '}'; } }
- Void set(Object obj, Object value):给obj对象的成员变量赋值value
- Class 类中获取成员变量的方法
-
5、反射获取成员方法并使用
- Class 类中用于获取成员方法的方法
- Method[] getMethods():返回所有公有成员方法对象的数组,包括继承的
- Method[] getMethod(String name, Class<?>... parameterTypes):返回单个公有成员方法对象
- Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
- Method[] getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象
- Method类中用于调用成员方法的方法
- Object invoke(Object obj, Object... args):调用obj对象的成员方法,参数时args,返回值是obj类型
package com.java.app; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Demo { @SuppressWarnings("all") public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException { // 获取Class对象 Class<?> c = Class.forName("com.java.app.Student"); // 获取无参构造器对象 Constructor<?> declaredConstructor = c.getDeclaredConstructor(); Object o = declaredConstructor.newInstance(); // 调用无参方法:method1() Method method1 = c.getDeclaredMethod("method1"); method1.setAccessible(true); // 取消访问检查 method1.invoke(o); // 调用带参数方法:method2() Method method2 = c.getDeclaredMethod("method2", String.class); method2.invoke(o, "java"); // 调用带参、有返回值方法:method3() Method method3 = c.getDeclaredMethod("method3", String.class, int.class); Object obj = method3.invoke(o, "java", 100); System.out.println(obj); } } class Student { public Student() { } private void method1() { System.out.println("method1"); } public void method2(String s) { System.out.println("method2: " + s); } public String method3(String s, int i) { return "method3: " + s + "--" + i; } }
- Object invoke(Object obj, Object... args):调用obj对象的成员方法,参数时args,返回值是obj类型
- Class 类中用于获取成员方法的方法
-
6、反射练习--越过泛型检查
package com.java.app; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; public class Demo { @SuppressWarnings("all") public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException { // 创建一个集合对象 ArrayList<Integer> arr = new ArrayList<Integer>(); // 获取Class对象 Class<?> c = ArrayList.class; // 获取method对象,通过Object.class绕过泛型检查 Method m = c.getMethod("add", Object.class); // 调用add方法,添加String类型的元素 m.invoke(arr, "hello"); m.invoke(arr, "world"); m.invoke(arr, "java"); System.out.println(arr); } }
获取方法对象时,传入Object.class是关键
-
7、反射练习--运行配置文件指定内容
package com.java.app; import jdk.jfr.events.FileReadEvent; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; public class Demo { @SuppressWarnings("all") public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException { // 加载配置文件数据 Properties prop = new Properties(); FileReader fr = new FileReader("E:\\ProgramFiles\\java_project\\Hello\\class.txt"); prop.load(fr); fr.close(); // 根据键获取值 String className = prop.getProperty("className"); String methodName = prop.getProperty("methodName"); // 根据配置文件获取指定的Class对象 Class<?> c = Class.forName(className); // 创建对象 Constructor<?> declaredConstructor = c.getDeclaredConstructor(); Object o = declaredConstructor.newInstance(); // 调用配置文件中指定的方法 Method method = c.getMethod(methodName); method.invoke(o); } }