数据流,对象流,序列化、反序列化,异常,继承,抽象类,反射

学习目标:

数据流,对象流,序列化、反序列化,异常,继承,抽象类,反射

学习内容:

1、数据流的使用
数据流: DataInputstream 和 DataOutputStream
DataOutputStream可以帮用户把各种java类型数据转成2进制写入文件流 writeInt(int i) writeLong(long l) writeFloat(float f) writeUTF(String s)
DataInputstream可以帮用户从文件流中直接读取出用户需要的数据 readInt() readLong() readFloat() readUTF()。
练习:

public class DataStreamExcersize {
	
	public static void main(String[] args) throws Exception {
		
		User u1 = new User("张三丰", 100, 10000.0f, 300000000);
		User u2 = new User("三毛", 10, 200.0f, 3);
		
		// 将这两个对象的数据写入文件
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:/u.dat"));

		dos.writeUTF(u1.getName());
		dos.writeInt(u1.getAge());
		dos.writeFloat(u1.getSalary());
		dos.writeLong(u1.getHairNum());
		
		dos.writeUTF(u2.getName());
		dos.writeInt(u2.getAge());
		dos.writeFloat(u2.getSalary());
		dos.writeLong(u2.getHairNum());
		
		dos.close();	
		// 从文件中读出数据,恢复对象
		DataInputStream dis = new DataInputStream(new FileInputStream("d:/u.dat"));
		String u1_name = dis.readUTF();
		int u1_age = dis.readInt();
		float u1_salary = dis.readFloat();
		long u1_hairNum = dis.readLong();
		
		User user1 = new User(u1_name, u1_age, u1_salary, u1_hairNum);
		User user2 = new User(dis.readUTF(), dis.readInt(), dis.readFloat(), dis.readLong());
		
		System.out.println(user1);
		System.out.println(user2);
		
		dis.close();	
	}
}

2、对象流的使用
对象流: ObjectOutputStream 和 ObjectInputStream
ObjectOutputStream可以帮用户直接把一个java的对象变成2进制写入文件流(或者网络流…),必要前提是:该java对象的类型必须实现serializable接口 implements Serializable(可序列化)。
ObjectInputStream可以帮用户从文件流(或者网络流)中读取2进制数据转成一个java对象。


 //对象输出流
public class ObjectOutputStreamDemo {
	public static void main(String[] args) throws Exception {
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/u.obj"));
		User user1 = new User("慕容复", 38, 2800, 8000);
		User user2 = new User("扫地僧", 58, 3800, 0);
		// writeObject(user)方法,要求user对象是可序列化的
		oos.writeObject(user1);
		oos.writeObject(user2);
		oos.close();
	}
}
//对象输入流
public class ObjectInputStreamDemo {
	public static void main(String[] args) throws Exception {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/u.obj"));
		User readObject1 = (User) ois.readObject();
		User readObject2 = (User) ois.readObject();
		System.out.println(readObject1);
		System.out.println(readObject2);
		ois.close();
	}
}

3、序列化和反序列化
只是一个概念:
将一个对象变成一个二进制数据序列 --> 这个过程叫序列化
反之,则称为反序列化。


 // 复杂类型对象的存、取  ---- 序列化和反序列化
 
public class FuzaObjectSerDe {
	
	@Test //可直接测试一个方法,不用再写main方法
	public  void testList() throws Exception {
		//  将一个list对象直接写入文件
		User user1 = new User("慕容复", 38, 2800, 8000);
		User user2 = new User("扫地僧", 58, 3800, 0);
		
		ArrayList<User> users = new ArrayList<>();
		users.add(user1);
		users.add(user2);

		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/users.list"));
		oos.writeObject(users);
		oos.close();
		
		// 从文件中读取一个list对象
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/users.list"));
		ArrayList<User> userList = (ArrayList<User>) ois.readObject();
		System.out.println(userList);
		ois.close();
	}
	
	 //将一个hashmap对象直接写入文件
	@Test
	public void testWriteMap() throws FileNotFoundException, IOException {
		HashMap<String, User> users = new HashMap<>();
		User user1 = new User("慕容复", 38, 2800, 8000);
		User user2 = new User("扫地僧", 58, 3800, 0);
		users.put(user1.getName(), user1);
		users.put(user2.getName(), user2);
		
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/users.map"));
		oos.writeObject(users);
		oos.close();
		
	}
	
	// 直接从文件中读取一个hashmap对象
	@Test
	public void testReadMap() throws Exception {
		// 从文件中读取一个list对象
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/users.map"));
		HashMap<String, User> userMap = (HashMap<String, User>) ois.readObject();
		System.out.println(userMap);
	}
	
	 //写入一个包含list成员的user对象
	 
	@Test
	public void testWriteUserWithList() throws FileNotFoundException, IOException {
		User user1 = new User("慕容复", 38, 2800, 8000);
		ArrayList<String> friends = new ArrayList<>();
		friends.add("王语嫣");
		friends.add("段誉");
		friends.add("虚竹");
		
		user1.setFriends(friends);
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/murongfu.obj"));
		oos.writeObject(user1);
		oos.close();
	}
}

4、java中的异常Exception处理
Exception是java对程序运行过程中可能出现的不可预料的不正常状态的一种描述。
具体的Exception有各种类型:比如数组脚标越界、list脚标越界、nullpoint异常、NumberFormat异常、ArithmeticException除0异常…
jvm在遇到异常时,会中止程序的执行,并打印出异常信息到控制台。后续代码不会被执行。

捕获异常
那么,我们在写程序时,如果遇到可能出现异常的语句,就可以在这个语句外面包围一个try-catch结构来捕获异常,以便于后续代码可以继续执行。
例:

int a=5;
int b= Integer.parseInt(scanner.nextLine());
try{
	int c = a/b;
}catch(Exception e){
	System.out.println(e.getMessage());
}
System.out.println("后续代码");

抛异常
抛异常可以直接抛给jvm: 就是说,在main方法中,不对可能出现异常的代码进行try-catch,下层方法可以把异常抛给上层调用者。
比如:定义一个方法,求商,方法声明会抛出异常。

public static int divide(int a,int b) throws Exception{
	return a/b;
}
// divide方法的调用者就能获得提示:如何处理异常
// 可以选择继续往上抛
main thows Exception {
	divide(5,0);
}
// 也可以选择将异常抓住,不再外抛了
main{
	try{
	   divide(5,0);
	}catch(Exception e){
	   sysout(e.getMessage());
	}
	
}

5、继承
整体作用:对同一类事物进行类定义时,很多的公共属性和方法,可以抽取到一个父类中;具体事物类只要继承这个父类,就拥有了它的属性和方法。

/** 定义一个父类 Person **/
public class Person{
	public String name;
	public int age;
	public float salry;
	public void say(){	
	}
	public void eat(){
		sysout("正在吃饭....")
	}
}
/** 定义一个子类 ChinesePerson **/
public class ChinesePerson extends Person{
	// 公共属性和方法就不需要重新定义了(父类中的私有属性和方法不会被继承)
	// 可以定义特有属性
	public String[] friends;
	// 可以定义特有方法
	public void makeFriends(String[] friends){
		this.friends = friends;
	}
	// 也可以重写父类中的方法
	@Override
	public void eat(){
		sysout("你好,吃了吗?");
	}
}

6、抽象类
抽象类一般用来作为一个父类,里面可以有方法是抽象的,以让子类来实现 。

//abstract 修饰符,表示这个类是一个抽象类
  //抽象类和普通类的区别:  抽象类中可以有抽象方法(只有方法定义,没有方法体)
public abstract class AbstractPerson {
	public String name;
	public int age;
	//abstract 声明这个方法是一个抽象方法
	public abstract void say();
	public void eat() {
		System.out.println("正在吃饭......");
	}
}
/** 继承了抽象类的子类  **/
public class JapaneseExtendsAbstractPerson extends AbstractPerson{
	/**
	 * 子类中必须实现抽象类中的抽象方法
	 */
	@Override
	public void say() {
		System.out.println("雅蠛蝶");
	}
}

7、 反射
最直观感受:通过一个字符串类名,就可以通过jdk的反射api来获得这个类的对象instance,还可以通过方法名和参数类型名 来反射出Method。然后可以用method.invok(instance,args)来调用用户所指定的方法。

classname = "com.doit.pojo.Person";
Class<?> forName = Class.forName(classname);
Person o = (Person)forName.newInstance();

反射的基本机制: 可以根据一个“类全名字符串” ,获得代表这个类的class对象,然后根据这个class对象构造出这个类的真正实例对象 。

String className="cn.edu360.javase24.reflect.demo.SerivceOne";
Class<?> forName = Class.forName(className);   // 根据类名字符串“SerivceOne”获取class对象
SerivceOne o = (SerivceOne)forName.newInstance();  // 用class对象构造出这个类SerivceOne的实例对象
o.say();String className="cn.edu360.javase24.reflect.demo.SerivceOne";
Class<?> forName = Class.forName(className);   // 根据类名字符串“SerivceOne”获取class对象
SerivceOne o = (SerivceOne)forName.newInstance();  // 用class对象构造出这个类SerivceOne的实例对象
o.say();

8、反射举例:
定义两个接口OneTwoService和OtherService,对这两个接口分别写两个实现类。

//OneTwoService接口
public interface OneTwoService {
	public void say();
}
//OneTwoServiceOneImpl实现类
public class OneTwoServiceOneImpl implements OneTwoService{
	@Override
	public void say() {
		System.out.println("我是one");
	}
}
//OneTwoServiceTwoImpl实现类
public class OneTwoServiceTwoImpl implements OneTwoService{
	@Override
	public void say() {
		System.out.println("我是Two");
	}
}
//OtherService接口
public interface OtherService {
	public void eat();
}
//OtherServiceOneImpl实现类
public class OtherServiceOneImpl implements OtherService{
	@Override
	public void eat() {
		System.out.println("我是otherserviceoneimpl中的eat方法....");
	}
}
//OtherServiceOneImpl实现类
public class OtherServiceTwoImpl implements OtherService{
	@Override
	public void eat() {
		System.out.println("我是otherservicetwoimpl中的eat方法....");
	}
}
//测试类
/**
 * 这就是一个典型的面向接口编程的程序
 * 
 * 它已经可以称之为一个框架
 * @author ThinkPad
 *
 */
public class Test {
	
	public static void main(String[] args) throws Exception {
		
		HashMap<String, String> applicationContext = new HashMap<>();
		
		/**
		 * 解析配置文件,将所有的接口名及其对应的要调用的实现类名放入一个hashmap中
		 */
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("f:/a.txt")));
		String line = "";
		while( (line = br.readLine())!=null  ) {
			//解析配置文件中的每一行
			String[] split = line.split(":");
			applicationContext.put(split[0], split[1]);
		}
		/**
		 *  先调一下OneTwoService的实现类的say方法
		 */
		
		Class<?> forName1 = Class.forName(applicationContext.get("OneTwoService"));
		OneTwoService newInstance1 = (OneTwoService) forName1.newInstance();
		newInstance1.say();
		/**
		 * 然后需要调OtherService的实现类的eat方法
		 */	
		Class<?> forName2 = Class.forName(applicationContext.get("OtherService"));
		OtherService newInstance2 = (OtherService) forName2.newInstance();
		newInstance2.eat();
	}
}
//反射机制中的方法调用
public class Test{
	public static void main(String[] args) throws Exception{
		String classname="cn.edu360.java24.day11.reflect.Person";
		String methodName="say";
		Class<?> forName=Class.forName(classname);
		Person p=(Person) forName.newInstance();
		//从forName这个class模板中获取到指定的方法
		Method method=forName.getMethod(methodName);
		Method methos2=forName.getMethod("eat",String.class);
		//将method在对象上执行
		Object invoke=method.invoke(p);
		System.out.println(invoke);
		Object invoke=method2.invoke(p,"饺子");
}
}
//若想类名和方法名可随意更换,可以通过main方法的args[]参数来实现。
/**
反射机制的补充:如何使用字符串信息来指定要调用的方法:
字符串指定要调用的方法名;
字符串指定要调用的方法的参数类型;

*/
public class Test{
	public static void main(String[] args) throws Exception{
		String classname=args[0];//要实例化的类名
		String methodName=args[1];//要调用的方法名
		Class<?> pClass=Class.forName(args[2]);//方法的参数类型
		String food=args[3];//调用方法时要传入的参数值
		Class<?> forName=Class.forName(classname);
		Person p=(Person) forName.newInstance();
		//从forName这个class模板中获取到指定的方法
		Method method=forName.getMethod(methodName);
		Method methos2=forName.getMethod("eat",String.class);
		//将method在对象上执行
		Object invoke=method.invoke(p);
		System.out.println(invoke);
		Object invoke=method2.invoke(p,"饺子");
		
}
}

args[]的配置方式:
右键选择Run As Configurations,如下图所示,参数间用空格隔开。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值