javase基础知识笔记
1.jdk下载与环境变量配置
- 下载官网:(https://www.oracle.com/index.html)
- 配置:变量名为JAVA_HOME, 变量值为安装路径如:E:\javahome, path值:%JAVA_HOME%bin
- win+R, 输入cmd, 回车,再输入javac -version回车查看版本,再输入 java -version 若都成功则配置安装成功。
2.基本数据类型(四型八种)
byte by = 123;//一个字节,八位
short sh = 456;//短整型,两个字节,16位
int i = 12332;//整型, 四个字节,32位
long lon = 23142342131L;//长整型,八个字节,64位
float fo = 175.9F;//单精度浮点型,四个字节,32位,
- 声明一个float类型变量,一个普通的小数默认是double类型
必须在常数的后面加上f或F double dou = 123.87;//双精度浮点型,八个字节,64位
boolean passed = false;//boolean类型,jvm中规定,计算机底层使用int类型存储Boolean类型,所以4字节
- //字符类型变量char,可以和int整型数据类型相互转换但是不能超过最大值,\表示转义字符
cha
r ch1 = ‘男’;System.out.println("a对应的字符型是:" + (char)a);//强制类型转换
- /强制类型转换,从高精度向低精度转换/(需要的低数据类型)高精度数据类型例如:
float f = (float)1212.121d;
3.短路与和短路或
- boolean bool = n1 > n2 && ++n1 > n3, 如果n1>n2为flase,则后面部分则不会被执行,称为短路与。
- boolean bool2 = n1 > n2 || --n1 >n3, 如果n1>n2为真,则后面不会被执行,称为短路或。
- 按位与&和按位或|:6661. 按位与和逻辑与相似,但不会出现短路现象,按位或亦是如此。
- 按位非~类似!
4.移位运算符
-
左移位,表示3向左移位2位, 左移位运算<< 左移一位相当于乘2,左移两位相当于乘2的2次方。
3 <<2(3为int型)
1)把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011,
2)把该数字高位(左侧)的两个零移出,其他的数字都朝左平移2位,
3)在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 1100,转换为十进制是12。
-
向左移动32位,结果和输入的数一样 * 原因:32%320,移动0位 * 如果向左移动33位,33%321,移动1位 结果:输入24,得到24 * 2^1 =48
-
右移位运算>>,右移一位相当于除2,右移n位相当于除2的n次方。无符号向右侧移动>>>,对负数有效变为正数,对整数和>>一样
5.循环
-
while循环:当条件为true时,可使用break;关键字跳出循环。continue;关键字表示结束本次循环,继续下一次循环。
/* * 计算出100以内所有偶数的和,偶数的和,并比较大小,输出 */ int a = 1; int odd_number_sum = 0;//奇数和 int even_number_sum = 0;//偶数和 while (a < 101) { if (a % 2 == 0) {//判断为偶数 even_number_sum += a; } else { odd_number_sum += a; } a++; }
-
do while循环:至少执行一次
/*生成随机数,用户输入0~5的数,猜数字游戏,do while循环至少执行一次 */ Scanner scanner = new Scanner(System.in); //生成一个随机数 Random random = new Random();//new一个生成随机数的对象 int randomNumber; int number; do { System.out.println("请输入一个范围在0~5的整数:"); number = scanner.nextInt(); randomNumber = random.nextInt(5);//随机生成一个小于5的整数 if (number == randomNumber) { System.out.println("恭喜你猜对了,随机数是" + randomNumber); } else { System.out.println("对不起,你猜错了,随机数是" + randomNumber); } } while (randomNumber != number);
-
for循环:
//打印九九乘法表 for (int i = 1; i <= 9; i++) {//外层循环控制换行 for (int j = 1; j <= i; j++) {//内层循环输出 System.out.print(j+ " x " + i + " = " + (i * j) + " "); } System.out.println();//换行 }
-
for循环迭代:
//for循环迭代 int[] nums = {12, 34, 567, 34, 1324, 12};//数组 for (int i : nums) { System.out.print(i + " "); }
6.冒泡排序
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
//冒泡排序
int temp;//临时变量
for (int i = 0; i < scores.length - 1; i++) {//外层循环控制总的排序次数
/*内层循环实现排序*/
for (int j = 0; j < scores.length - 1 - i; j++) {
/*对相邻两个数进行判断*/
if (scores[j] < scores[j + 1]) {
temp = scores[j];
scores[j] = scores[j + 1];
scores[j + 1] = temp;//依次比较将最小数置于末尾
}
}
}
/*使用冒泡排序递增排序*/
for (int i = 0; i < scores.length - 1; i++) {
for (int j = 0; j < scores.length - 1 - i; j++) {
if (scores[j + 1] < scores[j]) {
temp = scores[j + 1];
scores[j + 1] = scores[j];
scores[j] = temp;
}
}
}
7.数组
-
一维数组:
String[] names = {"小米", "小明", "莱昂纳多"};
静态方式创建数组 ,数组在JVM中采用栈和堆的储存方式,通过names在栈中地址访问堆(里面为数据)int[] nums = new int[5];//指定数组长度
int[] nums = {56, 28, 15, 999, 30, 65, 12, 77}; int temp;//临时变量 for (int i = 0; i < nums.length / 2; i++) { temp = nums[i]; nums[i] = nums[nums.length - (i + 1)]; nums[nums.length - (i + 1)] = temp; } for (int num : nums) { System.out.print(num + "\t"); }
-
二维数组
:int[][] stuScores;//声明二维数组变量
` stuScores = new int[3][3];//创建一个二维数组`
8.面向对象
-
java对象在JVM中储存:
Person person;
//声明一个自定义类型的局部变量,存储在JVM的栈中, 使用构造方法创建一个Person类型的对象;赋值给person变量, 对象存储在JVM的堆中;只有new才会在内存堆中新建一个对象person = new Person();
-
访问修饰符:
- public:公共的,最大访问级别。
- protected:保护的,不同包中只有子类允许访问。
- 缺省:默认的,不同包中不允许访问。
- private:私有的,只允许在本类中访问。
-
构造方法:
-
方法名称和类名完全相同,没有任何返回类型,这样的方法是构造方法(构造器)
-
构造方法是用来创建对象使用的,使用new 运算符调用并创建一个对象
-
带参数的构造器目的就是为对象进行成员属性初始化
/*局部变量和成员实例属性重合时可以使用this关键字指向成员变量*/ public Employee(String name, int workAge) { this.name = name; this.workAge = workAge; System.out.println(name + " " + workAge); }
-
如果构造器被定义多个称为构造方法重载或构造器重载,自定义有参构造器将会覆盖系统默认提供的无参构造器,如果需要使用则必须重新显示定义。
-
9.继承,多态,接口
- 继承:继承是类与类之间的关系,非对象与对象之间的关系,使用关键字extend, 创建子类对象时总是要先创建一个父类对象,默认子类的构造方法总是自动调用父类的无参构造方法 .
- java的三大特性:封装、继承、多态(方法重载、方法重写)。
- final关键字修饰的类不能被继承,构造方法不能被继承,final修饰的类不能被继承,不能被重写。
- 方法重载是在同一个类中,方法重写出现在子类当中
- super关键字,不能出现在静态方法中,super关键字在子类的构造方法中代表父类的构造器。
- 抽象类:
- Java核心编程思想是面向对象,面向对象核心编程思想是面向抽象。
- 不能使用final关键字修饰。
- 自身不能够实例化。
- 用来被继承。
- 适配器: 适配器(Adaptor)创建一个普通类作为适配器类,继承抽象类,实现所有抽象类方法,在用非抽象子类继承适配器,选择性重写抽象方法。
- 接口:接口中属性定义必须是公共的,静态的常量;接口中只允许定义公共的抽象的实例方法。接口中所有对象都是上转型对象。
10.静态代码块
-
允许访问静态属性,调用静态方法,定义局部变量及常量,定义局部类。
-
不允许访问实例属性和方法以及定义方法。
-
静态代码块属于类,和对象无关,随类的加载而加载。
/*定义静态的常量*/
private static final String DRIVER;
private static final String URL;
private static final String USER;
private static final String PASSWORD;
/*静态块
* 可以访问静态常量,静态变量,静态方法
* 定义静态内部类
* */
static {
//给常量赋值
DRIVER = "com.mysql.jdbc.Driver";
URL = "jdbc:mysql://localhost:3306/java";
USER = "root";
PASSWORD = "123456";
}
11.常用库介绍
-
Object类:
- 是所有类的超级父类,java任何引用类型对象都可以赋值给Object类型变量。
- Object类提供的常用方法:toString()方法;equals方法用来判定给定对象是否与当前对象相等;getClass方法返回当前对象的运行时类(Class)对象,此方法不允许子类进行重写:public final Class getClass();
-
Character包装类:
Character.isDigit(chars[i])
判断是否为数字Character.isLetter(chars[i])
判断是否为字母Character.isLowerCase(chars[i])
判断是否为小写字母Character.isUpperCase(chars[i])
判断是否为大写字母Character.toUpperCase(chars[i]);
字母转换为大写字母Character.toLowerCase(chars[i]);
字母转换为小写字母
-
Integer:
String strNumber = Integer.toString(number);//将整型转换为字符串
Integer.parseInt(String.valueOf(chars[i]));//将字符转换为字符串再转换整型
12.String字符串以及常用方法
-
String str=“IU”;字符串常量不可以被更改只能被覆盖;存储在jvm堆中的静态常量区.
-
toCharArray();
此方法返回char型数组. -
contains(" ")
判断是否包含空格 -
length();
返回字符串长度 -
String str3 = new String(chars, 3, 8);//aChinese,3:表示索引,8:索引开始取几个
-
比较两个字符串是否相等,equals比较的是字符串的序列化值是否相等,==比较值和是否是同一个对象
-
通过索引查找字符:
charAt(index);
-
判断结尾和开始:
startsWith("我爱中国")
,endsWith("qq.com");
-
去掉字符串前后的空格:
str.trim();
-
查找字符串中指定字符索引:
email.indexOf('@')
返回字符索引值email.indexOf(".com")
返回字符串索引email.indexOf('9',0)
从指定索引查找
-
str.split(tag);//返回一个字符串数组
-
提取字串:
substring(3);
从索引位置开始提取substring(3, 12);//3:开索引始,12:索引结束(最后不取该值)
-
toLowerCase();
转换为小写 -
toUpperCase();
转换为大写 -
replace("小", "大");//将小替换为大
-
StringBuffer:
StringBuffer buffer = new StringBuffer("^_^ ")
- StringBuffer是线上安全,线程同步的
buffer.append("qwq")
连接字符串
-
StringBuilder:
StringBuilder stringBuilder = new StringBuilder(base);//构建可变字符串
stringBuilder.toString();//返回连接的字符串
- 非线程同步,不涉及多线程使用比StringBuffer效率更高
13.日期和时间类
- SimpleDateFormat实现对Date的字符串格式化,是DateFormat的子类
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String birthday = sdf.format(this.birthday);//对日期对象进行格式化
Calendar对象的创建和使用(抽象类,不能实例化对象)日历
Calendar cal = Calendar.getInstance();//使用默认时区并指向当前系统时间创建一个日历实例
/*获取年月日*/
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;//月份从0开始到11,所以要加1
int date = cal.get(Calendar.DATE);
Date currentDate = cal.getTime();
获取当前日历对象所对应的date对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String strCurrentDate = sdf.format(currentDate);
set(int year,int month, int date);
设置日历的年份,月份,日期值
14.Math类
- 所有属性和方法都为static的,不需要创建实例,final修饰的终极类不能被继承
Math.abs(-12)
计算绝对值Math.cbrt(27.0)
计算立方根Math.max(a,b),Math.min(a,b)
比较大小Math.pow(x,y)
计算x的y次方Math.random()
返回0.0到1.0的随机数
15.集合
- Map接口(HashMap不是现程安全的。HashTable是线程同步的)
Map<String, Object> carMap = new HashMap<>(); /*存储键值对在哈希表*/ carMap.put("key0", car0);
carMap.put("key2", car2);
carMap.put("key3", car3);
carMap.get("key0")
通过键取值
/*获取所有键的集合*/ Set keySet = carMap.keySet();
不重复
/*取出哈希表中所有的值的集合*/ Collection coll = carMap.values();
carMap.containsKey("key0")
判断是否包含给定键
-
List集合
-
List<User> userList = new ArrayList<>();//创建List集合对象
-
userList.contains(new User())//判断集合中是否包含给定对象
-
userList.clear();
清空集合元素 -
:list中根据索引将元素数值改变(替换)注意 .set(index, element); 和 .add(index, element)
-
Vector集合实现类:向量集合,适用场景在处理多线程应用中
Vector<User> vector = new Vector<>();//创建集合向量
"当前集合是否为空:" + vector.isEmpty()
当前集合元素个数:" + vector.size())
vector.remove(user3);//删除元素
/*获取Vector独有的新方法提供元素枚举迭代器*/
Enumeration enu = vector.elements();
while (enu.hasMoreElements()) {
User user = (User) enu.nextElement();//将Object类型强制转换 System.out.println(user);
}
-
Set接口:没有索引,不能存储重复数据,会覆盖。(对象不能一样)
-
Set<Product> set = new HashSet<Product>(16);//指定初始容量,默认是16,会自动扩容
-
TreeSet类接口,排序,效率比HashSet要低
-
TreeSet类接口,排序
16.异常
- Throwable是所有异常的父类,Error错误重启java虚拟机才行,Exception异常修改代码可解决。
- 使用throws关键字声明异常,多个异常逗号隔开;使用throw关键字满足条件时抛出异常
try {//捕获异常
} catch (SQLException | IOException e) {//处理异常
String errorMessage = e.getMessage();//获取异常信息
System.err.println(errorMessage);
System.out.println(e.getClass().getName());
e.printStackTrace();
} finally {//强制执行块,用于释放被占用的资源
try { if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
17.File
常用构造方法:
- File(File dir,String child)
- File(String pathName)
- File(String parent,String child)
File resFile = new File("f:\\file\\java.data")
/*判断file对象是否在硬盘上存在*/
/*createNewFile方法必须确保被创建的文件的父目录都存在,否则出现IOException
* 系统找不到指定的路径。
* */
if (resFile.exists()) {
System.out.println("文件是可读的吗?" + resFile.canRead());
System.out.println("文件是可写入的嘛?" + resFile.canWrite());
System.out.println("文件绝对路径:" +
resFile.getAbsolutePath());//f:\file\java.data
System.out.println("基本路径:" + resFile.getPath());//f:\file\java.data
System.out.println("父路径:" + resFile.getParent());//f:\file
System.out.println("文件名称:" + resFile.getName());//java.data
/*判断文件是目录还是具体文件*/
System.out.println("文件是目录嘛?" + resFile.isDirectory());//false
System.out.println("具体文件:" + resFile.isFile());//true
// System.out.println(resFile.delete());//删除文件
18.输入流(InputStream对目标文件进行读取操作)
-
读取二进制文件,字节输入流:
/*建立目标要读取的文件对象*/ File file = new File(filePath); /*基于目标文件建立输入流*/ InputStream in = null; if (file.exists()) {//如果文件存在,创建文件输入流 try { in = new FileInputStream(file);//使用子类FileInputStream创建二进制输入流 int count = 0;//读取到的字节数 byte[] bytes = new byte[124];//临时存储读取到的二进制文件 /*将读取到的字节数存储到bytes字节中,每次从索引开始存储,存储的长度是 bytes.length,覆盖*/ while ((count = in.read(bytes, 0, bytes.length)) != -1) {//循环处理读取,读到文件末尾count为-1 String s = new String(bytes, 0, count);//索引0开始,读取长度count System.out.println(s); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close();//关闭流,释放资源 System.out.println("关闭成功"); } } catch (IOException e) { e.printStackTrace(); } } }
-
字符输入流:读取文本文件不会出现乱码
FileReader fileReader = null; if (file.exists()) { try { fileReader = new FileReader(file); int count = 0; char[] chars = new char[30]; while ((count = fileReader.read(chars, 0, chars.length)) != -1) { String s = new String(chars, 0, count); System.out.print(s); } } catch (IOException e) { e.printStackTrace(); }finally { try { if (fileReader != null) { fileReader.close();//关闭流,释放资源 System.out.println("关闭成功"); } } catch (IOException e) { e.printStackTrace(); } } }
-
使用BufferedReader缓冲流:提高效率(字符输入流)
FileReader fileReader = null;//基于文件的普通输入流 BufferedReader br = null;//基于某个Reader建立的字符缓冲流(处理流) if (file.exists()) { try { fileReader = new FileReader(file);//基于文件建立普通文本输入流 br = new BufferedReader(fileReader);//基于某个Reader建立文本缓冲流 int count = 0; char[] chars = new char[25]; while ((count = br.read(chars, 0, chars.length)) != -1) { String s = new String(chars, 0, count); System.out.print(s); } } catch (IOException e) { e.printStackTrace(); } finally { try { br.close(); fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } }
19.输出流(OutputStream对目标文件进行写入操作)
-
二进制输出流
public static void binaryOutputStream(File file) { String str = "start=D:\\java课程\\第十九天\\unit12 二级制输出流一(153).mp4"; byte[] bytes = str.getBytes();//将字符串转换为字节数组 OutputStream out = null; try { out = new FileOutputStream(file); out.write(bytes);//调用write方法将字节数组的数据写入目标文件file } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } }
-
数据比较大时使用缓冲流:
public static void useBufferedOutputStream(File file) { OutputStream os = null; BufferedOutputStream bs = null; String str = "君不见高堂明镜悲白发,朝如青丝暮成雪。"; byte[] bys = str.getBytes(); if (file.exists()) { try { System.out.println(file.getAbsolutePath()); os = new FileOutputStream(file.getAbsolutePath() + "/诗词.doc"); bs = new BufferedOutputStream(os);//基于某个OutputStream建立缓冲输出流 bs.write(bys, 0, bys.length);//写入目标文件 } catch (IOException e) { e.printStackTrace(); } finally { try { bs.close(); os.close(); } catch (IOException e) { e.printStackTrace(); } } } }
20.文件的复制(流的对接)
public static void copeFile(File target, File dir) {
InputStream in = null;//文件输入流,读取文件
OutputStream os = null;//文件输出流,写入文件
File copyFile = null;
if (target.exists()) {//判断目标文件是否存在
if (!dir.exists()) {//如果目录不存在,创建目录
dir.mkdirs();
}
try {
in = new FileInputStream(target);//基于文件建立输入流
String fileName = target.getName();//获取目标文件名称
/*避免文件重名被覆盖,可以拍使用系统时间的毫秒作为文件前缀*/
copyFile = new File(dir + "/" + new Date().getTime() + fileName);
os = new FileOutputStream(copyFile, Boolean.parseBoolean("utf-8"));//基于目标文件建立输出流
byte[] bytes = new byte[1024];//临时存储字节数据缓冲区
int count = 0;//记录读取内容的长度
while ((count = in.read(bytes, 0, bytes.length)) != -1) {
//文件复制读取中......
System.out.println("文件复制读取中......");
os.write(bytes, 0, count);//将临时缓冲区的内容写入目标文件
}
System.out.println("文件复制完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
os.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
21.序列化读写
-
序列化流,将一个java对象保存到目标文件(ObjectOutputStream)
public static void javaSerializableAction(Employee emp, File file) { OutputStream os = null; ObjectOutputStream oos = null;//序列化流 if (emp != null) { try { os = new FileOutputStream(file); oos = new ObjectOutputStream(os); oos.writeObject(emp);//将序列化文件保存到目标文件 } catch (IOException e) { e.printStackTrace(); } finally { try { oos.close(); os.close(); } catch (IOException e) { e.printStackTrace(); } } } }
-
反序列化流,从目标文件读取序列化java对象到内存(ObjectInputStream)
public static Employee deserializableJavaObject(File file) { InputStream in = null;//创建输入流 ObjectInputStream ois = null; Employee emp = null; if (file.exists()) {//如果文件存在 try { in = new FileInputStream(file); ois = new ObjectInputStream(in); //进行反序列化(串行化) Object object = ois.readObject(); emp = object != null ? (Employee) object : null; } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } return emp; }
22.多线程
-
Thread线程类
- 任何一个Thread实例调用start方法将启动运行一个线程
- Thread的run方法是线程启动后自动执行的业务方法
-
线程的生命周期
- 第一阶段:新建状态(此时线程还没有运行)
- 第二阶段:运行状态(线程开始运行并自动执行run方法)
- 第三阶段:中断状态(多种原因使线程处于终止)
- 第四阶段:死亡状态(释放线程对象,不在回复运行)
-
Runnable线程接口:有利于实现多个线程之间的数据共享,多个Thread实例共享此接口的run方法
-
interrupt()方法:中断某个线程的状态
-
线程之间的通信
-
同步代码块:被同步的代码块在一个线程对象进行访问时,其他线程是没有访问权限的,只有这个当前线程对象完全执行完了这个代码块,释放了同步锁,其它线程才可以访问这个代码块。
public class Syncode implements Runnable { @Override public void run() { synchronized (this) {//那个类调用就是那个对象,com.znzz.multiThread.SynCode@8e6ae55 Thread current = Thread.currentThread();//获取当前线程 for (int i = 0; i < 5; i++) { System.out.println("当前执行同步代码块的线程名称是:" + current.getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
-
对象同步锁:
public class SynObject implements Runnable { private Dog dog; public SynObject() { if (dog == null) { dog = new Dog(); } } @Override public void run() { synchronized (dog) {//对象同步锁 Thread current = Thread.currentThread();//获取当前线程 for (int i = 0; i < 5; i++) { System.out.println(current.getName() + "正在修改dog名字:"); dog.setName("米卡" + i); System.out.println("名字被修改为" + dog.getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
-
方法同步锁:
public class SynMethod implements Runnable { private double money = 100000; @Override public void run() { doMoney(); } private synchronized void doMoney() { Thread current = Thread.currentThread(); for (int i = 1; i <= 5; i++) { if (current.getName().equals("会计")) { System.out.println(current.getName() + " 正在入账......"); money *= i; System.out.println("账户:" + money); } if (current.getName().equals("出纳")) { System.out.println(current.getName() + " 正在分账......"); money = money * i - 0.2 * money; System.out.println("账户:" + money); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("总帐:" + money); } }
-
23.网络编程
- **IP地址:**IP 地址(Internet Protocol Address)是互联网协议特有的一种地址,它是 IP 协议提供的一种统一的地址格式。IP 地址为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。与域名绑定。
- **端口号:**ip地址是用来标志服务器的。但是一个服务器上会有很多个程序同时使用网络,那怎么保证他们的网络包不串线?好了,端口号就入场了,它是0-65535之间的一个数字。服务端是监听一个固定的端口,比如80,这样客户端在连接的时候都知道该连哪个应用。客户端是从未占用的里面随机挑选一个就可以(但一般不会选1024以下)。
24.枚举数据类型
- 枚举类用关键字enum修饰,用来定义不变的值,类似于final修饰的 常量;
- 枚举类中还可以定义方法,内部类,变量等,但都必须定义在枚举数据之后。
/*
枚举类型
* */
public enum SignalLamp {//交通信号灯
RED,
GREEN,
YELLOW;
/*后面定义其他类型及方法*/
private int num = 100;
static class InnerClass {
}
/*还可以定义接口*/
interface Dao {
}
}
25.反射编程
-
Java中的反射编程是通过JVM运行时获取某个类型的字节码(Class)对象,从而利用其反向获取此类型定义的内部信息实现编程的一种机制。
-
Class类:Class类的实例表示正在运行的Java应用程序中的类和接口,是字节码实例。
-
eg.
public static void main(String[] args) { try { Class<?> stuClass = Class.forName("com.znzz.practice.Student"); /*使用字节码对象获取关于这个类的对象实例*/ Student student = (Student) stuClass.newInstance();//默认调用此类的无参构造实例化对象,返回对象是Object类型 System.out.println(stuClass.getName());//com.znzz.practice.Student /*获取类的访问级别*/ System.out.println(stuClass.getModifiers() == Modifier.PUBLIC);//true /*获取所有公共级别的字段*/ Field[] fields = stuClass.getFields(); for (Field f : fields) { System.out.println(f);//public java.lang.String com.znzz.practice.Student.name } System.out.println("所有访问级别的字段数组长度:" + stuClass.getDeclaredFields().length);//3 /*获取类中定义的构造器*/ Constructor con0 = stuClass.getConstructor(String.class, Integer.class); System.out.println(con0 != null);//true /*获取所有构造器*/ Constructor[] constructors = stuClass.getConstructors(); System.out.println(constructors.length);//3个构造器 /*获取类中定义的方法*/ Method[] methods = stuClass.getMethods();//获取所有公共访问级别的方法,获取所有方法用stuClass.getDeclaredMethods() System.out.println(methods.length);//11包括父类中的方法 for (Method m : methods) { System.out.println(m.getName()); } } catch (Exception e) { e.printStackTrace(); } }
-
Constructor类:表示某个类的构造方法实例类型
public static void main(String[] args) { try { Class<?> stuClass = Class.forName("com.znzz.practice.Student");//获取字节码对象 /*获取构造器*/ Constructor cons = stuClass.getConstructor(String.class, Integer.class);//如果无参数就是无参构造器 /*使用构造器反射方法实现对象的创建*/ Student student = (Student) cons.newInstance("李知恩", 26);//返回Object类型,强制类型转换 System.out.println(student.getName() + " " + student.getAge()); System.out.println("构造器的参数个数是:" + cons.getParameterCount());//2 System.out.println(cons.getModifiers() == Modifier.PUBLIC);//构造器的访问级别 true System.out.println(cons.getName());//com.znzz.practice.Student } catch (Exception e) { e.printStackTrace(); } }
-
Filed和Method类反射编程:Field提供有关类或接口的单个字段信息,以及对它的动态访问权限。
public class TestFieldAndMethod { public static void main(String[] args) { try { Class<?> stuClass = Class.forName("com.znzz.practice.Student");//加载类 Student student = (Student) stuClass.newInstance();//通过反射获取一个实例对象 /*获取某个成员字段*/ Field nameField = stuClass.getField("name");//获取公共级别的属性字段 nameField.set(student, "lisa");//为公共字段赋值 /*使用反射获取某个对象字段的属性值*/ System.out.println(nameField.get(student));//lisa /*获取不可见的字段属性private*/ Field ageField = stuClass.getDeclaredField("age"); if (ageField.getModifiers() == Modifier.PRIVATE) { /*运行时动态改变私有字段的访问级别*/ ageField.setAccessible(true);//访问级别设置为public ageField.set(student, 28); System.out.println(ageField.get(student));//28 } Field sexField = stuClass.getDeclaredField("sex"); if (!sexField.isAccessible()) { sexField.setAccessible(true); sexField.set(student, "女"); System.out.println(sexField.get(student)); } /*Method反射编程*/ Book book = new Book(); book.setName("《红楼梦》"); Method method = stuClass.getMethod("learn", Book.class);//方法名,参数类型 method.invoke(student, book);//执行方法 /*获取非公共可见级别的方法*/ Method method2 = stuClass.getDeclaredMethod("run"); if (!method2.isAccessible()) {//如果访问级别不是公共可见的 method2.setAccessible(true);//运行时更改此方法的访问级别 method2.invoke(student); } } catch (Exception e) { e.printStackTrace(); } } }