Java面向对象小白必读——学习笔记(二)

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)

  1. 导包@Test
  2. 写测试的方法,不要有参数,也不要返回
  3. 右键运行Test方法

集合

  • 装数据的容器

ArrayList

  1. 底层是一个数组实现
  2. 线程不安全,效率高
  3. 若有设置的初始容量使用设置的初始容量,默认初始容量0,加1个元素扩容到10 加载因子1 扩容1.5倍
  4. 是有序的,索引
  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

  1. 无序,不可重复
  2. 初始容量是16(2的n次方) 加载因子0.75 扩容2倍
  3. 底层用HashMap(保存数据),实现Set接口
  4. 若有设置初始容量,则使用大于此初始容量的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
  1. throws 写在方法后面,表示这个方法可能出现的异常都抛给调用者处理,谁调用谁处理。

  2. 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);

四层模型

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值