Java核心类库
Object(万类之祖)
toString
- 直接打印一个引用数据类型,默认调用的是这个对象的toString方法
Person p = new Person();
System.out.println(p);
System.out.println(p.toString);
equals
- ==使用在基本数据类型中比较的是指,在引用数据类型中比较的事地址
Person p = new Person();
Person p2 = new Person();
System.out.println(p == p2);
- 输出为false(因为p和p2各开辟了一个空间,地址值不同)
- equals不能用在基本数据类型上,只能用来比较引用数据类型,比较的也是地址
Test
p.name = "王胖子";
p.age = 18;
p2.name = "王胖子";
p2.age = 20;
System.out.println(p.equals(p2));
Person
package practice_06_Object;
public class Person {
public String name;
public String sex;
public int age;
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
返回值为true,当name不一样时为false
clone
-
让类实现接口Cloneable
-
重写clone方法,扩大访问作用域
Person
public class Person implements Cloneable{
public String name ;
public String sex ;
public int age ;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
*Test*
public class Demo02 {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person();
p.name = "王胖子";
p.age = 18 ;
p.sex = "男";
/*
*
* 1,让Person实现接口Cloneable
* 2,重写clone方法,扩大访问作用域
*
* 浅拷贝
*
*/
Person p2 = (Person) p.clone() ;
System.out.println(p.toString());
System.out.println(p2);
}
}
包装类
一、什么是包装类
- Java中的基本数据类型没有方法和属性,而包装类就是为了让这些拥有方法和属性,实现对象化交互。
二、基本数据和包装类之间的转换
装箱、拆箱
-
自动装箱
当你需要包装类的时候,给的是基本数据类型。
-
自动拆箱
当你需要基本数据类型的时候,给的是包装类。
public class Test {
public static void main(String[] args) {
//1.自动装箱
int t1 = 12;
Integer t2 = t1;
//2.手动装箱
Integer t3 = new Integer(t1);
System.out.println("int类型t1:"+t1);
System.out.println("自动装箱:"+t2);
System.out.println("手动装箱:"+t3);
//1.自动拆箱
int t4 = t2;
//2.手动拆箱
int t5 = t2.intValue(); //通过intValue()方法返回int值,还可以利用其他方法装换为其他类型
System.out.println("自动拆箱,int型t4="+t4);
System.out.println("手动拆箱,int型t5="+t5);
}
}
三、基本数据类型和包装类之间的转换
-
通过包装类Integer.toString()将整型转换为字符串;
-
通过Integer.parseInt()将字符串转换为int类型;
-
通过valueOf()方法把字符串转换为包装类然后通过自动拆箱。
public class Test_01 {
public static void main(String[] args) {
int t1 = 12;
String t2 = Integer.toString(t1);
System.out.println("int转换为String:" + t2);
System.out.println(t2 instanceof String);
// 字符串转换为基本数据类型,通过paerInt方法
int t3 = Integer.parseInt(t2);
// 通过valeOf,先把字符串转换为包装类然后通过自动拆箱
int t4 = Integer.valueOf(t2);
System.out.println("t3:" + t3);
System.out.println("t4:" + t4);
}
}
四、包装类对象之间的比较
包装类对象的初始值为null(是一个对象)
package practice_12;
public class Test_02 {
public static void main(String[] args) {
Integer t1 = new Integer(88);
Integer t2 = new Integer(88);
//t1、t2是两个不同的对象
System.out.println(t1==t2);//地址不同
System.out.println(t1.equals(t2));//值相同
Integer t3 = 100;//自动装箱
//这时缓存区没有,就会自欧东构造一个对象Integer t3 = Integer.valueOf(100);
System.out.println(t3 instanceof Integer);//t3属于Integer
//因为Integer类型的取值范围在-128——127之间,当装箱的值超出这个范围的时候会阴性的new一个空间
Integer t4 = 200;//超出范围,重新构建一个空间
Integer t5 = 200;//超出范围,重新构建一个空间
System.out.println(t4==t5);//t4、t5是两个新空间,地址不同
System.out.println(t4.equals(t5));//值相同
System.out.println(Integer.toBinaryString(t4));
System.out.println(Integer.toHexString(t4));
System.out.println(Integer.toOctalString(t4));
Integer t6 = new Integer("88");
System.out.println(t6 instanceof Integer);
int t7 = Integer.parseInt("88");
System.out.println(t7);
}
}
单元测试(junit)
- 导包@Test
- 写测试的方法,不要有参数,也不要返回
- 右键运行Test方法
集合
- 装数据的容器
ArrayList
- 底层是一个数组实现
- 线程不安全,效率高
- 若有设置的初始容量使用设置的初始容量,默认初始容量0,加1个元素扩容到10 加载因子1 扩容1.5倍
- 是有序的,索引
- 可以重复
- api基本用法:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test_05 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
list.add("g");
list.add("h");
list.add("d");
//利用循环删除集合所有元素
// for (int i = 0; i < list.size(); ) {
// list.remove(i);
// }
// Object[] arr = list.toArray();
// System.out.println(Arrays.toString(arr));
list.add(2,"aa");//在第三个位置添加一个元素
list.remove(2);//移除第三个元素
list.add("a");//添加到最后一个
// list.clear(); 清空所有元素
System.out.println(list.get(5));//获取第五个元素
System.out.println(list.size());//输出该集合总元素
System.out.println(list.contains("v"));//检测是否包含v
System.out.println(list.contains("b"));//检测是否包含b
System.out.println(list.indexOf("d"));//第一个d所在的位置
System.out.println(list.lastIndexOf("d"));//最后一和d所在的位置
//遍历集合
for(String name : list) {
System.out.print(name+ " ");
}
}
}
HashSet
- 无序,不可重复
- 初始容量是16(2的n次方) 加载因子0.75 扩容2倍
- 底层用HashMap(保存数据),实现Set接口
- 若有设置初始容量,则使用大于此初始容量的2的幂。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test_06 {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e");
//1.hasNext 跟 next 调用1对1
//遍历
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()) {
System.out.print(iterator.next()+" ");
}
}
}
HashMap
- Map是用来存两个字段的 <键,值>
- Map的key不能重复,重复的话后面的覆盖前面的
- hashcode在hash开头的集合里面,(HashMap HashSet HashTable)
- 默认初始容量是16(2的n次方) 加载因子0.75,扩容2倍
- 若有设置初始容量,则使用大于此初始容量的最小2的幂。
- 线程不安全,效率高
- 支持key跟value为null,只有一个key为null,值可以多个NULL
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.junit.Test;
public class Demo {
@Test
public void testHashMap() {
Map<String,String> m = new HashMap<String,String>();
m.put("name", "zhaowen");
m.put("age", "18");
m.put("sex", "男");
m.put("sex", "女");//覆盖上一行
//检测是否含有该元素
System.out.println(m.containsKey("name"));
System.out.println(m.containsValue("19"));
// m.remove("age");
System.out.println(m.size());//获取集合元素多少
//遍历values
Collection<String> values = m.values();
for (String string : values) {
System.out.println(string);
}
//遍历key
Set<String> keySet = m.keySet();//把所有的key拿出来放在Set集合中
for(String string : keySet) {
System.out.println(string);
}
//遍历<key,values>
Set<Entry<String,String>> entrySet = m.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey()+"------"+entry.getValue());
}
}
}
HashMap的4种遍历方式
package com.bailiban.day13_HomeWork02;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
public class Test2 {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<String,String>();
map.put("001","wenwen");
map.put("002","kunkun");
map.put("003","tiantian");
map.put("003","tiantian");
//1. 通过Map.values()遍历所有的value,但不能遍历key
for (String values : map.values()) {
System.out.println(values);
}
System.out.println("-----------------------");
//2.通过Map.keySet遍历key和value
for (String key : map.keySet()) {
System.out.println("key:"+key+"; values:"+map.get(key));
}
System.out.println("-----------------------");
//3.通过Map.entrySet遍历key和value
for(Entry<String, String> entry : map.entrySet()){
System.out.println("key: "+ entry.getKey() + "; value: " + entry.getValue());
}
System.out.println("-----------------------");
//4.通过Map.entrySet使用iterator遍历key和value
Iterator<Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()){
Entry<String, String> entry = it.next();
System.out.println("key: "+ entry.getKey() + "; value: " + entry.getValue());
}
}
}
底层结构
(1.8)底层结构是 数组+链表+红黑树
- hash冲突(hash碰撞):不同的关键码 经过hash算法以后得到了相同值。
- 首先把Key经过hashcode和hash得到一个整数值。
- 将这个整数值跟数组table的长度取余数。这个余数就是存的数组的索引。
- 如果2个Key得到的索引相同(有2个元素存在同一个桶里面),先通过equals进行判断,如果为true表示是相同(逻辑上)的对象,那么就进行覆盖。如果equals返回时的false,表示是不同的元素,只是发生了hash冲突,那么就以链表的形式接在后面。
- 当一个链表的长度达到了8,并且数组的长度达到了64,会把链表结构转成红黑树。如果没有达到64则把数组扩容。
- 当一个红黑树元素当减少到6个时候结构再转换成链表。
Vector
// 线程安全的,效率低
// <> 代表限制集合中存放的数据类型,意思定义什么类型,集合就只能放这种类型的元素 。
List<String> v = new Vector<String>();
v.add("aa");// 添加元素
集合总结
ArrayList
默认初始容量0,加1个元素扩容到10 加载因子1 扩容1.5倍
底层数据结构是数组结构
线程不安全,效率高
若有设置的初始容量使用设置的初始容量。
Vector
默认初始容量10 加载因子1 扩容2倍
底层数据结构是数组结构
线程安全,效率低
若有设置的初始容量使用设置的初始容量。
HashSet
初始容量是16(2的n次方) 加载因子0.75 扩容2倍
底层实现是一个HashMap(保存数据),实现Set接口
若有设置初始容量,则使用大于此初始容量的2的幂。
TreeSet
底层结构是TreeMap (红黑树–2叉树中的一种)
TreeSet线程不安全,性能不如HashSet
但是有序(String自然顺序,不是插入顺序),不可重复
插入元素如果为非基本类型则需要可比性(Comparable)
================================================================
HashMap
默认初始容量是16(2的n次方) 加载因子0.75 扩容2倍
若有设置初始容量,则使用大于此初始容量的最小2的幂。
线程不安全,效率高
支持key跟value为null
HashTable
默认初始容量为11,加载因子为0.75 扩容2倍+1
线程安全,效率低
若有设置初始容量,则使用此值。
不支持key跟value为null
TreeMap
底层结构是红黑树(2叉树中的一种)
TreeMap线程不安全, 有序(String自然顺序(定制顺序),不是插入顺序)
插入元素如果为非基本类型则需要可比性(Comparable)
key不能为null,值可以为null
================================================================
案例
- 斗地主
package Poker;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo {
public static void main(String[] args) {
//1.准备玩家
List<String> zhourunfa = new ArrayList<String>();
List<String> zhouxingchi = new ArrayList<String>();
List<String> liudehua = new ArrayList<String>();
List<String> poker = new ArrayList<String>();
//2.准备牌
poker.add("大王");
poker.add("小王");
String number [] = {"3","4","5","6","7","8","9","10","J","Q","K","A","2",};
String color [] = {"♠","♥","♣","♦"};
for(String n : number) {
for(String c : color) {
poker.add(c+n);
}
}
//3.洗牌 随机
Collections.shuffle(poker);
//4.发牌
for (int i = 0; i < poker.size()-3; i++) {
if (i%3==0) {
zhourunfa.add(poker.get(i));
}else if (i%3==1) {
zhouxingchi.add(poker.get(i));
}else {
liudehua.add(poker.get(i));
}
}
//5.看牌
for (String p : zhourunfa) {
System.out.print(p+" ");
}
System.out.println();
for (String p : zhouxingchi) {
System.out.print(p+" ");
}
System.out.println();
for (String p : liudehua) {
System.out.print(p+" ");
}
}
}
异常
概述
程序的执行跟我们的预期不一致,需要对这种意外情况进行捕获处理。
异常分类
ERROR:不可修复的问题
Exception:可以捕获跟处理,改变流程。不要专门为了改变流程使用
运行时异常:代码在运行期间出现的异常。
编译时异常:代码在运行前就提示的异常。
###发生了异常信息,跳转到异常处理流程,下面的代码不执行。###
Error:它是所有的错误类的父类。它是Throwable的子类。
Exception: 它是所有异常类的父类。它是Throwable的子类。
RuntimeException:运行时异常。所以运行时异常都需要继承此类。
Exception:此类的是编译异常。
我们可以通过多个catch块来进行多种异常处理,多种异常需要按照一定的顺序,越父类越后面,越之类越前面。
finally
- 写在catch块后面的,写在最后的,而且只能写一个。
- 一般回收资源的代码写在里面。
- 即使try块中直接return,finally块里面的代码也会执行
异常处理机制
- try catch
try{
需要监控的代码
}catch(Exception e){
处理代码
}
- throws
-
throws 写在方法后面,表示这个方法可能出现的异常都抛给调用者处理,谁调用谁处理。
-
throws 是可以抛出多个异常的,没有顺序
什么时候要使用异常处理
- 有发生异常也必须处理的需求,比如释放资源,跟IO相关
- 编译异常必须处理
- 如果出现异常需要特殊处理。比如记录日志。
自定义异常
-
自定义运行时异常
//自定义运行时异常 public class AgeOutOfBoundException extends RuntimeException { public AgeOutOfBoundException(){ } public AgeOutOfBoundException(String s){ super(s); } }
-
自定义编译异常
//自定义编译异常 public class AgeOutOfBoundException extends Exception { public AgeOutOfBoundException(){ } public AgeOutOfBoundException(String s){ super(s); } }
IO
概述
使用数据通讯的通道。
什么是IO
输入输出流,使用数据通讯的通道
File
java代码是可以操作硬盘上的文件的,因为硬盘上的文件可以映射为java内存中的File,我们直接操作内存中的File,就可以间接的操作硬盘上的文件
File API
delete 删除此抽象路径名表示的文件或目录。
equals(Object obj)
测试此抽象路径名与给定对象是否相等。
exists()` 测试此抽象路径名表示的文件或目录是否存在。
IO分类
输入/输出 字节/字符
- 字节输入流
- 字节输出流
- 字符输入流
- 字符输出流
文本文件的读取
建立输入流——建立包装流——创建File找到(e://b/12.txt)——用输入流读取File——用包装流包装输入流读取的——循环打印包装的东西——关闭包装流——关闭输入流
/***
* 字符:读取这个txt文件中的所有内容,并在控制台打印
* */
FileReader fr = null;// 建立输入流
BufferedReader br = null;// 建立输入流的包装流
try {
File file = new File("e://b/12.txt");
fr = new FileReader(file);
br = new BufferedReader(fr);
String s = null;
// 循环读取文件中的内容,并打印在控制台上
while ((s = br.readLine()) != null) {
System.out.println(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 两层流,先关闭外层的包装流,在关闭里面的输入流
try {
if (br != null) {
br.close();
}
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
文件文本的写入
建立输出流——建立包装流——创建所写文件——用输出流判断是为覆盖还是追加——用包装流包装输出流——写入内容(包装流)——关闭包装流——关闭输出流
File file = new File("e://b/b.txt");// 创建需要写入的文件
FileWriter fw = null;// 建立输出流
BufferedWriter bw = null;// 建立输出流的包装流
try {
fw = new FileWriter(file, true);// false 默认为覆盖,true为追加
bw = new BufferedWriter(fw);
// 往流里写入内容
bw.write("这是写的第一句话\n");// 斜杠n也代表换行
bw.write("这是写的第二句话");
bw.newLine();// 换行
bw.write("这是写的第三句话\n");
bw.write("这是写的第四句话");
bw.flush();// 刷新该流的缓冲
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if (bw != null) {
bw.close();
}
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
图片的复制
创建输入、输出流——创建原文件、目标文件(将原文件里的图片复制到目标文件中)——输入流读取原目标数据——输出流接收数据——创建byte数组——循环传输数据——关闭流
/**
* 字节流: 目标:复制一个图片到另一个地方 流是占资源的,需要释放
* **/
// 先创建目标文件
FileInputStream fis = null;// 从文件系统中的某个文件中获得输入字节
FileOutputStream fos = null;
// 文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流
try {
// 创建我们需要的流,输入字节流
File target = new File("e://b/1.png");// 创建目标文件(即复制到的图片在这个里面)
File src = new File("e://a/1.png");// 把a文件夹里的1.png图片复制到b文件夹里面
fis = new FileInputStream(src);// 输入流,用来读取原目标的数据
fos = new FileOutputStream(target);// 输出流,用来接收来自输入流的数据
byte[] b = new byte[1024];// 定义一个byte字节,用于装接受到的字节
int i = -1;
while ((i = fis.read(b)) != -1) {// 读取数据放入b中,返回结果是读取多少有效数据
// read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
System.out.println(i);// 把每次读取到的数据通过输出流写到目标文件中
fos.write(b, 0, i);
// write(byte[] b, int off, int len),将指定 byte 数组中从偏移量 off 开始的len个
// 字节写入此文件输出流。
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源,关闭流
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
枚举
定义固定数量的对象
public class TraLightColor {
public static TraLightColor red = new TraLightColor();
public static TraLightColor green = new TraLightColor();
public static TraLightColor yellow = new TraLightColor();
// 构造方法私有化,只有本类中可以调用
private TraLightColor(){
}
}
枚举
上面的方式比较麻烦,我们可以使用枚举的方式来达到目的:初始化好固定数量的对象,直接使用。除此以外,其它的用法跟类差不多。
- 枚举的定义
public enum WeekDay {
// 创建并初始化好固定数量的对象,类型为当前类型(WeekDay)
MON,TUE,WED,THU,FRI,SAT,SUN ;
// WeekDay MON ;
// WeekDay TUE ;
}
-
枚举的构造方法必须是private
-
如果枚举的构造方法带参数,则定义枚举值得时候必须传值,且能匹配到对应类型(数量/个数/顺序)的构造方法
-
枚举中可以定义属性跟方法
-
所有的枚举都默认继承Enum ,所以不能再继承其它的类
-
枚举值需要写在最上面,扩展的内容写在后面
-
枚举也可以实现方法
public enum WeekDay implements EnumInterface { /* * 所有的枚举都默认继承Enum ,所以不能再继承其它的类 * 枚举值需要写在最上面 * * name:枚举值的字符串 * ordinal:枚举值对应的索引 */ // 创建并初始化好固定数量的对象,类型为当前类型(WeekDay) MON("星期1",0),TUE("星期2",1),WED("星期3",2),THU("星期4",3),FRI("星期5",4),SAT("星期6",5),SUN("星期7",6) ; private String weekName ; private int weekOrdinal ; // static WeekDay MON = new WeekDay("星期1"); // static WeekDay TUE = new WeekDay("星期2"); // 默认定义一个无参数的private的构造方法,必须是private private WeekDay(String name,int count){ // System.out.println("我是WeekDay的私有的构造方法。。"+name); this.weekName = name; this.weekOrdinal = count ; } public String getWeekName(){ return weekName ; } public int getWeekOrdinal(){ return weekOrdinal; } public void study(){ System.out.println("好好学习,天天向上。"); } @Override public void method() { System.out.println("这是接口中的方法实现。。。。"); } }
switch case
WeekDay d4 = WeekDay.WED;
switch (d4) {
case MON:// 直接写枚举值即可,不需要类型(WeekDay)
System.out.println("今天星期1,吃热干面");
break;
case TUE:
System.out.println("今天星期2,吃油条");
break;
case WED:
System.out.println("今天星期3,吃牛肉面");
break;
default:
break;
}
内部类
- 一个java文件中,必须有且仅有一个public修饰class,且修饰的class名字必须跟文件名一样。
- 内部类分类
- 成员内部类
- 临时内部类
- 静态内部类
- 匿名内部类
成员内部类
public class Outter {
public String name ;
public int age ;
public int i = 1 ;
// 成员内部类
public class Inner{
public String sex ;
public int i = 2 ;
public void innermethod(){
System.out.println("你好啊,今天才星期2,都趴下了。");
}
}
public void outterMethod(){
System.out.println("--- outterMethod ---");
}
}
- 成员内部类对象必须必须依赖外部类的对象
- 当外部类跟内部类有冲突,this表示内部类的,Outter.this表示外部类中的。
- 内部可以外部的,外部不能访问内部的。
- 成员内部类不能定义静态的内容
- 成员内部类编译成class文件后, 外部类$内部类
临时内部类
public void outterMethod(){
int a = 1 ;
class TempClass{
public String tempName ="";
public void tempMethod(){
}
}
TempClass t = new TempClass();
t.tempMethod();
}
- 一般不会用到。
静态内部类
public class Outter2 {
public String name = "outName" ;
public static int age ;
public int i = 1 ;
static class StaticClass{
public String sex = "男" ;
public int i = 2 ;
public void staticMethod(){
System.out.println("----staticMethod---");
}
}
public void outterMethod(){
System.out.println("----outter2Method-----");
}
}
- 静态内部类不需要依赖于外部类对象,可以直接new一个静态内部类的对象
- 静态内部类不能访问外部类的非静态内容
匿名内部类
MyInterface my = new MyInterface(){
public String name = "hello";
@Override
public void interMethod() {
System.out.println("---interMethod---"+name);
}
};
my.interMethod();
DemoClass demo = new DemoClass(){
public String name ;
@Override
public void demoMethod() {
System.out.println("-----override demo method ------");
method2();
}
public void method2(){
System.out.println("----- demo method2 ------");
}
};
demo.demoMethod();
Properties
-
properties文件中注释是使用#号
-
数据用键值对,键值中间用=隔开,也可以使用:号跟空格,但是一般我们都用=号
name=zhangsan age=18 sex=男
读取properties内容
// 创建对应的属性文件
File file = new File("src/com/blb/seven04/demo.properties");
// 建立到文件之间的流
FileInputStream fis = new FileInputStream(file);
InputStreamReader read = new InputStreamReader(fis,"utf-8");
// 通过流把配置文件中的数据加载到Properties对象中。
Properties p = new Properties();
p.load(read);
// 遍历所有内容
Enumeration<Object> keys = p.keys();
while(keys.hasMoreElements()){
String s = (String) keys.nextElement();
System.out.println( s+ " "+ p.getProperty(s));
}
写Properties内容
// 创建对应的属性文件
File file = new File("src/com/blb/seven04/demo1.properties");
if(!file.exists()){
file.createNewFile();
}
Properties p = new Properties();
p.setProperty("name", "seven");
p.setProperty("age", "22");
p.setProperty("sex", "女");
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
p.store(osw,"版权归seven所有");
案例
模仿软件试用期,假设该软件只有五天(次)的试用期,过了时间即抛出异常。这就是一个简单的配置文件。
File file = new File("src/com/blb/seven05/software.properties");
if(!file.exists()){
file.createNewFile();
}
FileInputStream fis = new FileInputStream(file);
Properties p = new Properties();
p.load(fis);
String count = p.getProperty("count");
if(Objects.isNull(count)){
p.setProperty("count", "1");
}else{
int c = Integer.parseInt(count);
c++;
if(c>5){
System.out.println("使用次数达到上限,请购买。");
return ;
//throw new RuntimeException("使用次数达到上限,请购买。");
}else{
p.setProperty("count", ""+c);
}
}
FileOutputStream fos = new FileOutputStream(file);
p.store(fos, "");
反射
获取Class对象的3种方式
// 反射第1步永远是拿到这个类的Class
// 第1种方式:
Class clazz = Person.class ;
// 第2种:
// Class clazz2 = Class.forName("com.blb.seven01.Person");
// 第3种方式:
// Person p = new Person();
// Class class1 = p.getClass();
创建对象
// 2,创建对象:newInstance 调用无参构造方法去创建对象
// Person person = (Person) clazz.newInstance();
//
// 获取某一个构造器
Constructor c1 = clazz.getDeclaredConstructor(String.class,int.class);
c1.setAccessible(true);//调用私有的都需要给权限
// 通过构造器来实例化对象,需要传具体的参数值 new Person("zhangsan",18)
Person person = (Person) c1.newInstance("zhangsan",18);
System.out.println(person);
person.study();
/*
* getConstructor : 获取public类型构造器
* getDeclaredConstructor:获取定义的构造器(包括私有的)
*/
通过反射使用属性
/*
* getDeclaredFields:获取本类所有的属性,包括私有的
* getFields : 获取所有的public的属性,包括继承过来的。
*
*/
// 获取Class对象
Class clazz = Student.class;
// 获取构造器
Constructor c = clazz.getDeclaredConstructor(String.class);
c.setAccessible(true);
// 通过构造器获取对象
Student s = (Student) c.newInstance("student");
// 获取所有的声明的属性
// Field[] fields = clazz.getDeclaredFields();
// for (Field field : fields) {
// System.out.println(field.getName());
// }
// 获取某一个指定的字段
Field f = clazz.getDeclaredField("number");
// 因为是私有的,需要给权限
f.setAccessible(true);
// 设置值的时候需要指定对象,因为属性不能独立存在,需要依赖对象
f.set(s, "102");
System.out.println(s);