JAVASE笔记

介绍:

两种核心机制:

1.JAVA虚拟机(JAVA Virtual Maachine),JVM :一编写,处处运行

2.垃圾回收机制(Garbage Collection),GC :自动进行

面向对象的三大特征:

封装 (Encapsulation)继承 (Inheritance)多态 (Polymorphism)

数据类型:

(8种基本):

整型:

byte(1字节):-128- 127

short(2字节)

int(4字节)

long(8字节)

浮点型:

float 4字节:7位有效数字 float = 1.22f

double 8字节:16位有效数字 double = 1.22

字符:

char(16位):’‘

布尔类型:

boolean:在true和false中不能用0和非0表示,无null

引用类型:

String:可以使用null作为值(会存储在字符串常量池中)

String s0 = “hello”;

String s1=“hello”

内存中只会存在一个hello(与C++区分

备注:

byte short char之间不会相互转换,只会先转换成int类型再进行计算

对象的产生

Person m = new Person();

sout(m) == sout(m.toString)//地址需要override

当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。除了基本数据类型之外的变量类型都是引用类型.

成员变量类型初始值
byte0
short0
int0
long0L
float0.0F
double0.0D
char‘\u0000’(表示为空)
booleanfalse
引用类型null

Instanceo操作符

x instanceof A:检验x是否为类A的对象,返回值为boolean型。

要求x所属的类与类A必须是子类和父类的关系,否则编译错误。如果x属于类A的子类B,x instanceof A值也为true。

Object 类

Object类是所有Java类的根父类

如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类

public class Person { … }

等价于:public class Person extends Object {…}

例:method(Object obj){…} //可以接收任何类作为其参数

Person o=new Person();

method(o);

Object类中的主要方法

NO.方法名称类型描述
1public Object()构造构造方法
2public boolean equals(Object obj)普通对象比较
3public int hashCode()普通取得Hash码
4public String toString()普通对象打印时调用(打印对象地址)

对Java对象的强制类型转换称为造型

对Java对象的强制类型转换称为造型

从子类到父类的类型转换可以自动进行

从父类到子类的类型转换必须通过造型(强制类型转换)实现

Person p = new Person();

Student s = (Student)p;

无继承关系的引用类型间的转换是非法的

==操作符与equals方法

equals():所有类都继承了Object,也就获得了equals()方法。

还可以重写。只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象。

格式:obj1.equals(obj2)特例:当用equals()方法进行比较时,对类File、String、Date及包装类(Wrapper Class)来说,是比较类型及内容而不考虑引用的是否是同一个对象;

原因:在这些类中重写了Object类的equals()方法。

包装类(Wrapper)

基本数据类型包装类
booleanBoolean
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble

字符串转换成基本数据类型通过包装类的构造器实现:

主要:为了基本数据类型与字符串直接的转化

int i = Integer.parseInt("123"); //字符串转整型

String intstr = String.valueof(i); //整型转字符串

int i = new Integer(“12”);

通过包装类的parseXxx(String s)静态方法:

Float f = Float.parseFloat(“12.1”); //字符串转换成float类型

基本数据类型转换成字符串调用字符串重载的valueOf()方法:

String fstr = String.valueOf(2.34f);

更直接的方式:

String intStr = 5 + “”

匿名对象

我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。如:new Person().shout();

使用情况如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。 我们经常将匿名对象作为实参传递给一个方法调用。

说明:

1.可变参数:方法参数部分指定类型的参数个数是可变多个

2.声明方式:方法名(参数的类型名…参数名)

3.可变参数方法的使用与方法参数部分使用数组是一致的

4.方法的参数部分有可变形参,需要放在形参声明的最后

内存模型

Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。

image-20240803183838350

可变个数的形参

//下面采用数组形参来定义方法public static void test(int a ,String[] books); //如果没有参数就要定义空数组null

//以可变个数形参来定义方法public static void test(int a ,String…books); //可以不写test();

Static注意情况:

1.类的访问机制:在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。(例外:static方法访问非static的成员变量,编译不通过。

在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。

2.重写和被重写的方法须同时为static的,或同时为非static的

3.因为不需要实例就可以访问static方法,因此static方法内部不能有this。(也不能有super ? YES!)重载的方法需要同时为static的或者非static的。

虚拟方法调用

正常的方法调用

Person p = new Person();  	

p.getInfo();  	

Student s = new Student();   	

s.getInfo();  虚拟方法调用(多态情况下)  	

Person e = new Student();    	

e.getInfo();

调用Student类的getInfo()方法 编译时类型和运行时类型编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。——动态绑定

接口

接口的特点:用interface来定义。接口中的所有成员变量都默认是由public static final修饰的。接口中的所有方法都默认是由public abstract修饰的。接口没有构造器。接口采用多层继承机制

匿名内部类

匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。

一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。

new 父类构造器(实参列表)|实现接口(){ //匿名内部类的类体部分}

捕获/抛出异常:

捕获异常:

捕获异常的有关信息:与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。

try{}catch(Exception e){

e.printStackTrace();

or

sout(“e.getMessage()”);

}finally //可写可不写

{}

getMessage( ) 方法,用来得到有关异常事件的信息

printStackTrace( )用来跟踪异常事件发生时执行堆栈的内容。

抛出异常:

方法中抛出,调用时捕获

class B{
    int i;
    public void test() throws Exception{
        B b =null;
        System.out.println(b.i);
    }
}
public class JavaBean {
    public static void main(String[] args) {
        B b = new B();
        try {
            b.test();
        }catch (Exception e){
            e.printStackTrace();
        }

​    }
}

Java集合

Java集合类存放于 java.util 包中,是一个用来存放对象的容器。

①、集合只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。

②、集合存放的是多个对象的引用,对象本身还是放在堆内存中。

③、集合可以存放不同类型,不限数量的数据类型。

Java 集合可分为 Set、List 和 Map 三种大体系

Set:无序、不可重复的集合 (TreeSet进行自然排序)

List:有序,可重复的集合

Map:具有映射关系的集合在 JDK5 之后,增加了泛型,Java 集合可以记住容器中对象的数据类型

HashSet

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。

我们大多数时候说的set集合指的都是HashSetHashSet

按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。

HashSet 具有以下特点:

1.不能保证元素的排列顺序

2.不可重复

3.HashSet 不是线程安全的

集合元素可以使 null当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置

如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

image-20240530101735707

Set s = new HashSet(); = Set<Object> s = new HashSet<Object>();

s.add(1);

s.remove(1);

s.contains(1); //true //是否包含1

s.clear();

s.size()

元素的遍历:

Iterator It = s.iterator();

while(It.hashNext()){

​	sout(It.next());

}
for (Object obj:set){    /把set的每一个值取出来赋值给obj,直到循环set的所有值
    System.out.println(obj);
}

泛型和TreeSet集合

Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段

让集合存同样类型的对象

Set<String> set = new HashSet<set>();//不能存string类型之外的数据了

Set<Integer> set = new TreeSet<Integer>();
------------------------------------------------------------
main:
Person p1 = new Person("张三",23);
		Person p2 = new Person("李四",20);
		Person p3 = new Person("王五",16);
		Person p4 = new Person("Lucy",29);
		
		Set<Person> set = new TreeSet<Person>(new Person()); //其中的new Person()是一个比较器
		set.add(p1);
		set.add(p2);
		set.add(p3);
		set.add(p4);
		
		for(Person p : set){
			System.out.println(p.name + "   " + p.age);
		}
		
	}
------------
class Person implements Comparator<Person>{//把person对象存到TreeSet中并且按照年龄排序
	int age;
	String name;
	
	public Person(){
		
	}
	
	public Person(String name, int age){
		this.name = name;
		this.age = age;
	}

	@Override
	public int compare(Person o1, Person o2) {//年龄正序排列
		if(o1.age > o2.age){
			return 1;
		}else if(o1.age < o2.age){
			return -1;
		}else{
			return 0;
		}
	}

List集合

List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引

List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。

List 默认按元素的添加顺序设置元素的索引。

List 集合里添加了一些根据索引来操作集合元素的方法

image-20240530161208185

	List<String> list = new ArrayList<String>();
		list.add("b");//第一个,索引下标0
		list.add("d");//索引下标1
		list.add("c");//索引下标2
		list.add("a");//索引下标3
		list.add("d");//允许使用重复元素
	System.out.println(list);
	System.out.println(list.get(2));//通过索引来访问指定位置的集合元素
	
	list.add(1,"f");//在指定索引下标的位置插入数据
	System.out.println(list);
	
	List<String> l = new ArrayList<String>();
	l.add("123");
	l.add("456");
	
	list.addAll(2, l);//在指定索引下标的位置插入集合
	
	System.out.println(list);
	
	System.out.println(list.indexOf("d"));//获取指定元素在集合中第一次出现的索引下标
	System.out.println(list.lastIndexOf("d"));//获取指定元素在集合中最后一次出现的索引下标
	
	list.remove(2);//根据指定的索引下标移除元素
	System.out.println(list);
	
	list.set(1, "ff");//根据指定的索引下标修改元素
	System.out.println(list);
	
	//根据索引下标的起始位置截取一段元素形参一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
	List<String> sublist =  list.subList(2, 4);//取索引下标在大于等于2小于4的元素
	
	System.out.println(sublist);
	
	System.out.println(list.size());//集合的长度

不可变list集合

List l = List.of(“1”,“2”); //其它集合Set、Map(最多10个:用ofEntries)都有of方法创建不可变集合

内容不可修改

for(String s :l){

​ sout(s);

}

Map

HashMap

image-20240530163119251

       		Map<String, Integer> map = new HashMap<String, Integer>();
		map.put("b", 1);//添加数据
		map.put("c", 2);
		map.put("e", 2);
		System.out.println(map);

		System.out.println(map.get("b"));//根据key取值

		map.remove("c");//根据key移除键值对
		System.out.println(map);

		System.out.println(map.size());//map集合的长度

		System.out.println(map.containsKey("a"));//判断当前的map集合是否包含指定的key

		System.out.println(map.containsValue(10));//判断当前的map集合是否包含指定的value

		map.clear();//清空集合

		Set<String> keys = map.keySet();//获取map集合的key的集合

		map.values();//获取集合的所有value值

		//遍历map集合,通过map.keySet();
		for(String key : keys){
			System.out.println("key: " + key + ", value: " + map.get(key));
		}

		//通过map.entrySet();遍历map集合
		Set<Entry<String, Integer>> entrys = map.entrySet();
		for(Entry<String, Integer> en : entrys){
			System.out.println("key: " + en.getKey() + ", value: " + en.getValue());
		}

Treemap

	//TreeMap的自然排序是字典排序
	Map<Integer,String> map = new TreeMap<Integer, String>();
	map.put(4, "a");
	map.put(2, "a");
	map.put(3, "a");
	map.put(1, "a");
	
	System.out.println(map);
	
	Map<String,String> map1 = new TreeMap<String, String>();
	map1.put("b", "b");
	map1.put("c", "c");
	map1.put("d", "d");
	map1.put("a", "a");
	map1.put("ab", "ab");
	map1.put("1", "ab");
	map1.put("10", "ab");
	
	System.out.println(map1);

Collections(操作集合的工具)

排序操作:

reverse(List):反转 List 中元素的顺序

shuffle(List):对 List 集合元素进行随机排序

sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序

sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序

swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素

Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素

Object min(Collection)

Object min(Collection,Comparator)

int frequency(Collection,Object):返回指定集合中指定元素的出现次数

boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值

同步控制

Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题

image-20240530172031388

泛型类

1.对象实例化时不指定泛型,默认为:Object。

2.泛型不同的引用不能相互赋值。

public class Test1 {
	public static void main(String[] args) {
//		B1<Object> b1 = new B1<Object>();
//		B1<String> b2 = new B1<String>();
//		
//		B2 b3 = new B2();
		

		Cc<Object> c = new Cc<Object>();
		c.test("xxx");
		//泛型方法,在调用之前没有固定的数据类型
		//在调用时,传入的参数是什么类型,就会把泛型改成什么类型
		//也就是说,泛型方法会在调用时确定泛型距离数据类型
		Integer i = c.test1(2);//传递的参数是Integer,泛型就固定成Integer,返回值就是Integer
		Boolean b = c.test1(true);//传递的参数是Boolean,泛型就固定成Boolean,返回值就是Boolean
	}

}

interface IB<T>{
	T test(T t);
}

/**

 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中

 * @author lby
   *

 * @param <T>
   */
   class B1<T> implements IB<T>{

   @Override
   public T test(T t) {
   	return t;
   }

}

/**

 * 如果实现接口时指定接口的泛型的具体数据类型

 * 这个类实现接口所有方法的位置都要泛型替换实际的具体数据类型

 * @author lby
   *
    */
   class B2 implements IB<String>{

   @Override
   public String test(String t) {
   	return null;
   }

}
class Cc<E>{
	private E e;
	
	/**
	 * 静态方法的泛型方法
	 * @param t
	 */
	public static <T> void test3(T t){
		//在静态方法中,不能使用类定义泛型,如果要使用泛型,只能使用静态方法自己定义的泛型
//		System.out.println(this.e);
		System.out.println(t);
	}
	
	/**
	 * 无返回值的泛型方法
	 * @param s
	 */
	public <T> void test(T s){
		//在类上定义的泛型,可以在普通的方法中使用
		System.out.println(this.e);
		T t = s;
	}
	
	/**
	 * 有返回值的泛型方法
	 * @param s
	 */
	public <T> T test1(T s){
		return s;
	}
	
	/**
	 * 形参为可变参数的泛型方法
	 * @param strs
	 */
	public <T> void test2(T... strs){
		for(T s : strs){
			System.out.println(s);
		}
	}
}

枚举类

在某些情况下,一个类的对象是有限而且固定的。

例如季节类,只能有 4 个对象手动实现枚举类:private 修饰构造器

属性使用 private final 修饰

把该类的所有实例都使用 public static final 来修饰

image-20240530203933347

public class Test3 {
	public static void main(String[] args) {
		//Season.SPRING,这段执行就是获取一个Season的对象
		Season spring = Season.SPRING;
		spring.showInfo();
		

		Season summer = Season.SUMMER;
		summer.showInfo();
		
		Season spring1 = Season.SPRING;
		//每次执行Season.SPRING获得是相同的对象,枚举类中的每个枚举都是单例模式的
		System.out.println(spring.equals(spring1));
		spring1.test();
		
	}

}

enum Season implements ITest{
	SPRING("春天","春暖花开"),//此处相当于在调用有参的私有构造private Season(String name,String desc)
	SUMMER("夏天","炎炎夏日"),
	AUTUMN("秋天","秋高气爽"),
	WINTER("冬天","寒风凛冽");
	

	private final String name;
	private final String desc;
	
	private Season(String name,String desc){
		this.name = name;
		this.desc = desc;
	}
	
	public void showInfo(){
		System.out.println(this.name + ": " + this.desc);
	}
	
	@Override
	public void test() {
		System.out.println("这是实现的ITest接口的test方法");
	}

}

interface ITest{
	void test();
}

@Annotation(注解) 概述

image-20240530210106176

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

自定义注解

image-20240530211614188

I/O流:File 类

image-20240530222009756

文件的遍历:

	//遍历d盘下的test文件,把test文件夹下所有的目录与文件全部遍历出来,不论层级有多深,要全部遍历出来
	//这个使用递归的方式来实现
	File f = new File("D:\\test");
	new Test().test(f);
	
}

/**
 * 递归遍历文件
 * @param file
 */
public void test(File file){
	if(file.isFile()){
		System.out.println(file.getAbsolutePath() + " 是文件");
	}else{
		System.out.println(file.getAbsolutePath() + " 是文件夹");
		//如果是文件夹,这个文件夹里就可能有子文件夹或者文件
		File[] fs = file.listFiles();//获取当前文件夹下的子文件夹或者文件的file对象
		if(fs != null && fs.length > 0){
			for(File ff : fs){
				
				test(ff);//递归		
							}
		}
		
	}
}

流的分类

按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)

按数据流的流向不同分为:输入流,输出流

按流的角色的不同分为:节点流,处理流

定义文件路径时,注意:

可以用“/”或者“\”。 在写入一个文件时,如果目录下有同名文件将被覆盖。

在读取文件时,必须保证该文件已存在,否则出异常。

(抽象基类)字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

文件字节流

/**
	 * 文件字节输入流FileInputStream
	 * 。
	 *  在读取文件时,必须保证该文件已存在,否则出异常
	 */
	public static void testFileInputStream(){
		try {
			FileInputStream in = new FileInputStream("D:/test/abc/tt1.txt");
			
			byte[] b = new byte[10];//设置一个byte数组接收读取的文件的内容
			
			int len = 0;//设置一个读取数据的长度
			
//			in.read(b);//in.read方法有一个返回值,返回值是读取的数据的长度,如果读取到最后一个数据,还会向后读一个,这个时候返回值就是-1
			//也就意味着当in.read的返回值是-1的时候整个文件就读取完毕了
			
			while((len = in.read(b)) != -1){
				System.out.println(new String(b,0,len));
				//new String(b,0,len),参数1是缓冲数据的数组,参数2是从数组的那个位置开始转化字符串,参数3是总共转化几个字节
			}
			
			in.close();//注意。流在使用完毕之后一段要关闭
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 文件字节输出流FileOutputStream
	 * 在写入一个文件时,如果目录下有同名文件将被覆盖
	 */
	public static void testFileOutputStream(){
		try {
			FileOutputStream out = new FileOutputStream("D:/test/abc/tt4.txt");//指定行tt4输出数据
			String str = "knsasjadkajsdkjsa";
			out.write(str.getBytes());//把数据写到内存
			out.flush();//把内存中的数据刷写到硬盘
			out.close();//关闭流
			
					} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 复制文件到指定位置
	 * @param inPath 源文件路径
	 * @param outPanth 复制到的文件夹位置
	 */
	public static void copyFile(String inPath, String outPanth){
		try {
			FileInputStream in = new FileInputStream(inPath);//读取的源文件
			
			FileOutputStream out = new FileOutputStream(outPanth);//复制到哪里
			
			byte[] b = new byte[100];
			
			int len = 0;
			
			while((len = in.read(b)) != -1){
				out.write(b, 0, len);//参数1是写的缓冲数组,参数2是从数组的那个位置开始,参数3是获取的数组的总长度
			}
			
			out.flush();//把写到内存的数据刷到硬盘
			out.close();
			in.close();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

文件字符流

	public static void main(String[] args) {
		Test2.testFileReader("D:/test/abc/tt1.txt");
		//在写入一个文件时,如果目录下有同名文件将被覆盖。
//		Test2.testFileWriter("!!!!!!!", "D:/test/abc/tt5.txt");
		
//		Test2.copyFile("D:/test/abc/tt5.txt", "D:/test/abc/cc/tt5.txt");
	}
	
	/**
	 * 文件字符输入流FileReader
	 *  在读取文件时,必须保证该文件已存在,否则出异常
	 * @param inPath
	 */
	public static void testFileReader(String inPath){
		try {
			FileReader fr = new FileReader(inPath);//创建文件字符输入流的对象
			
			char[] c = new char[10];//创建临时存数据的字符数组
			
			int len = 0;//定义一个输入流的读取长度
			
			while((len = fr.read(c)) != -1){
				System.out.println(new String(c, 0, len));
			}
			
			fr.close();//关闭流
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 文件字符输出流FileWriter
	 * 在写入一个文件时,如果目录下有同名文件将被覆盖
	 * @param text 输出的内容
	 * @param outPath 输出的文件
	 */
	public static void testFileWriter(String text,String outPath){
		try {
			FileWriter fw = new FileWriter(outPath);
			fw.write(text);//写到内存中
			fw.flush();//把内存的数据刷到硬盘
			fw.close();//关闭流
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 字符流完成拷贝文件,字符流只适合操作内容是字符文件
	 * @param inPaht
	 * @param outPath
	 */
	public static void copyFile(String inPaht, String outPath){
		try {
			FileReader fr = new FileReader(inPaht);
			FileWriter fw = new FileWriter(outPath);
			
			char[] c = new char[100];
			
			int len = 0;
			
			while((len = fr.read(c)) != -1){//读取数据
				fw.write(c,0,len);//写数据到内存
			}
			
			fw.flush();
			
			fw.close();
			fr.close();
					} catch (Exception e) {
			e.printStackTrace();
		}

缓冲字符流

为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组

**BufferedInputStream 和 BufferedOutputStream **

BufferedReader 和 BufferedWriter

public static void main(String[] args) {
		try {
//			Test.testBufferedInputStream();
//			Test.testBufferedOutputStream();
			Test.copyFile();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}/**
 * 缓冲字节输入流
 * BufferedInputStream
 * @throws Exception 
 */
public static void testBufferedInputStream() throws Exception{
	//文件字节输入流对象
	FileInputStream in = new FileInputStream("D:\\testdemo\\demo\\src\\day13\\tt.txt");
	
	//把文件字节输入流放到缓冲字节输入流对象
	BufferedInputStream br = new BufferedInputStream(in);
	
	byte[] b = new byte[10];
	
	int len = 0;
	
	while((len = br.read(b)) != -1){
		System.out.println(new String(b,0,len));
	}
	
	//关闭流的时候,本着一个最晚开的最早关,依次关
	br.close();
	in.close();
}

/**
 * 缓冲字节输出流
 * BufferedOutputStream
 */
public static void testBufferedOutputStream() throws Exception{
	//创建字节输出流对象
	FileOutputStream out = new FileOutputStream("D:\\testdemo\\demo\\src\\day13\\tt1.txt");
	
	//把字节输出流对象放到缓冲字节输出流中
	BufferedOutputStream bo = new BufferedOutputStream(out);
	
	String s = "hello world";
	
	bo.write(s.getBytes());//写到内存中
	
	bo.flush();//刷到硬盘上
	
	//关闭流的时候,本着一个最晚开的最早关,依次关
	bo.close();
	out.close();
	
}

/**
 * 缓冲流实现文件的复制
 */
public static void copyFile() throws Exception{
	//缓冲输入流
	BufferedInputStream br = new BufferedInputStream(new FileInputStream("D:\\testdemo\\demo\\src\\day13\\tt1.txt"));
	
	//缓冲输出流
	BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream("D:\\testdemo\\demo\\src\\day13\\tt2.txt"));
	
	byte[] b = new byte[1024];
	
	int len = 0;//设置一个没出读取到的数据的长度,直到br.read方法执行到最后(比如说文件中只有hello world,执行到最后一个就读取d的后面,这个时候返回值就是-1)
	
	while((len = br.read(b)) != -1){
		bo.write(b, 0, len);//写到内存
	}
	
	bo.flush();//刷到硬盘
	
	bo.close();
	br.close();
}

对于输出的缓冲流,写出的数据会先在内存中缓存,使用flush()将会使内存中的数据立刻写出

转换流

/**
 * 转换流
 * 可以把字节流转换为字符流
 * 当字节流中的数据都是字符的时候,使用转换流转为字符流处理效率更高
 * @author lby
 *
 */
public class Test2 {
	public static void main(String[] args) {
		//所有的文件都是有编码格式
		//对于我们来说,TXT和java文件一般来讲有三种编码
		//ISO8859-1,西欧编码,是纯粹英文编码,不适应汉字
		//GBK和UTF-8,这两编码是适用于重要和英文
		//我们一般使用UTF-8编码
		
		try {
//			Test2.testInputStreamReader();
			Test2.testOutputStreamWriter();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 转换字节输入流为字符输入流
	 * 注意,在转换字符流的时候,设置的字符集编码要与读取的文件的数据的编码一致
	 * 不然就会出现乱码
	 * InputStreamReader
	 */
	public static void testInputStreamReader() throws Exception{
		FileInputStream fs = new FileInputStream("D:\\testdemo\\demo\\src\\day13\\tt5.txt");
		
		//把字节流转换为字符流
		InputStreamReader in = new InputStreamReader(fs,"GBK");//参数1是字节流,参数2是编码
//		InputStreamReader in = new InputStreamReader(fs,"UTF-8");//参数1是字节流,参数2是编码
		
		char[] c = new char[100];
		int len = 0;
		
		while((len = in.read(c)) != -1){
			System.out.println(new String(c,0,len));
		}
		
		in.close();
		fs.close();
	}
	
	/**
	 * 转换字节输出流为字符输出流
	 * 注意,在转换字符流的时候,设置的字符集编码要与读取的文件的数据的编码一致
	 * 不然就会出现乱码
	 * OutputStreamWriter
	 */
	public static void testOutputStreamWriter() throws Exception{
		FileOutputStream out = new FileOutputStream("D:\\testdemo\\demo\\src\\day13\\tt6.txt");
		
//		OutputStreamWriter os = new OutputStreamWriter(out, "UTF-8");
		OutputStreamWriter os = new OutputStreamWriter(out, "GBK");
		
		os.write("你好你好");
		os.flush();
		
		os.close();
		out.close();
	}
}

Class类(反射)

调用过程:

Class p = Person.class;

Constructor con = p.getConstructor(); //获取无参构造

Object obj = con.newInstance();          //使用无参构造创建对象

Methode m = p.getMethod("test",String.class,int.class); //获取方法名为test,参数为一个String类型的

//Methode m = p.getDeclareMethod("test",String.class,int.class); //调用私有方法

//m.setAccessible(true); 		//接触私有的封装

m.invoke(obj,"hell",1);				    //开始调用,hell是实际参数

线程

首先新写一个类(MyThread)继承Thread类,实现runnable接口;

class Test extends Thread{
}

1.重写Tread 的run()【也可以实现多线程】

Thread d = new Test();

d.start( );

//多线程

//1.实现Runable接口
class MyRunnable implements Runnable{
//2.覆盖run()方法
    @Override
    public void run() {
        for (int i=0;i<=20;i++){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"----"+i);//获取当前线程名
        }

    }
}
public class RunnableTest {
    public static void main(String[] args) {
        //3.创建MyRunnable的实例
        MyRunnable task=new MyRunnable();
        //4.通过task对象来创建Thread对象
        Thread thread1=new Thread(task);
        //5.启动线程
        thread1.start();


        Thread thread2=new Thread(task);
        thread2.start();

    }
}

2.实现Runnable接口实现多线程

Thread d = new Thread(new test(),"线程名称");

d.start( );

方法:

d.setName(String ""); //设置线程名字
d.getName();
d.currentTread();
d.yield();    //线程让步   执行机会让给优先级相同或更高的
d.join();     //线程插入
d.sleep();  //线程睡眠ms
d.stop()    //强制停止线程

优先级:

getPriority();				  //获取新城优先级
setPriority(int newPriority); //设置线程优先级  默认5  1-10

锁:

public synchroized void draw(){} //在普通对象上加锁,锁的是对象不是方法 (只是针对某一个对象)(解决:对static的对象加锁)

线程通信

wait(); //令当前线程挂起

notify();唤醒正在排队的线程

notifyAll();唤醒正在排队的所有等待线程

这三个方法只能用在有同步锁的方法

线程池

image-20240604114643009

API

Math–API

Math.max(int a,int b);
round();
ceil();//向上(正:负数也是)取整
floor();
PI = 3.14...;
pow(int a,int b);//a的b次幂
sqrt();
cbrt();  	//开立方
random(); 	//[0,1)之间的随机数

System

System.exit();//0:正常停止 其他:异常停止 
long l = System.currentTimeMillis(); //获取系统运行时间
System.arraycopy(arr1,0,arr2,0,10);//(拷贝数组1)->2   (数组1,第几索引开始拷,数组2,从几索引开始贴,拷贝数量)

Runtime

Runtime.getRuntime().availableProcessors();//获取内核数
Runtime.getRuntime().maxMemory();//获取可用内存
Runtime.getRuntime().exec("nitepad"); //运行cmd命令

正则表达式

String qq = "123456";
qq.matches("[1-9]\\d{5,19}")  //5-19位
\s:一个空白字符
\S:非空白字符
\w:[1-9a-z_A-Z]
\W:非单词
\\d:  //数字
\\D:  //非数字
X {?,*,+} //  1/0  0-n  1-n
X {n,m}   //n-m次
-? :  //可出现可不出现
(?!)java: //忽略大小写
(java)(?:8|11); //?代表java(可以单独)  后边跟着8或者11
(java)(8|11); //必须java后跟着8|11

捕获分组:
(.)\\1:         //.表示任意字符   \\1表示把第一组(第几组主要看左括号“(”)的字符再次拿出来使用

String str="我学学学嘻嘻嘻";
String re = str.replaceAll(regex:"(.)\\1+",replacement:"$1"); //正则内用\\1  正则外用$1

非捕获分组:(?:)(?=)(?!)
更多使用第一个(?:)  不占组号  //?:中的?也是代表前边,见到知道是非捕获分组即可
String regex = "[1-9]\\d{16}(?://d|X|x)"   //身份证号

image-20240602214941792

Lambda表达式

简化匿名内部类书写:只有@FunctionInterface

Arrays.sort(arr,(Integer o1,Integer o2)->{

​ return o1-o2; //升序排序

})

序列化

流:ObjectOutputStream(内存->文件)和ObjectInputStream(文件->内存)

需要实现空接口:

class Student implements Serializable{}  //此对象可以序列化
属性:public transient String address;    //瞬态关键字:该关键字标记的成员变量不参与序列化过程

打印流

字符和字节打印流:PrintWrite和PrintStream

image-20240604104444863

网络编程

B/S:浏览器/服务器
C/S:客户端/服务器

三要素:

1、IP:设备在网络上的地址,唯一标识

2、端口号:应用程序在设备中唯一的标识

3、协议:数据在网络中传输的规则

UDP:

DatagramSocket d = new DatagramSocket();               //创建对象(快递公司)数据包
String s = "hello";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.*getByName*("127.0.0.1");
int port =10086;
DatagramPacket s1 = new DatagramPacket(bytes,bytes.length,address,port); //打包数据
d.send(s1); //发送数据
d.close(); //释放资源

image-20240604143346383

上边都是单播1:1

组播

224.0.0.0-239.255.255.255

MuticastSocket创建对象

TCP

image-20240604144809680

发送数据:

image-20240604144932563

接受数据

image-20240604145336981

image-20240604150245893

image-20240604150217553

反射

​ class是指当前类的class对象,getClassLoader()是获取当前的类加载器,什么是类加载器?简单点说,就是用来加载java类的,类加载器负责把class文件加载进内存中,并创建一个java.lang.Class类的一个实例,也就是class对象,并且每个类的类加载器都不相同。getResourceAsStream(path)是用来获取资源的,而类加载器默认是从classPath下获取资源的,因为这下面有class文件吗,所以这段代码总的意思是通过类加载器在classPath目录下获取资源.并且是以流的形式。

​ 我们知道在Java中所有的类都是通过加载器加载到虚拟机中的,而且类加载器之间存在父子关系,就是子知道父,父不知道子,这样不同的子加载的类型之间是无法访问的(虽然它们都被放在方法区中),所以在这里通过当前类的加载器来加载资源也就是保证是和类类型同一个加载器加载的。

原文链接:https://blog.csdn.net/feeltouch/article/details/83796764

image-20240604151225649

获取class对象;

Class.forName(“类名”);//包名+类名

类名.class

对象.getClass();

image-20240604151716961

获取构造方法:

image-20240604151920946

image-20240604152116472

image-20240604153338217

image-20240604153403751

类、实例和Class对象区分

类是面向对象编程语言的一个重要概念,它是对一项事物的抽象概括,可以包含该事物的一些属性定义,以及操作属性的方法。面向对象编程中,我们都是以类来编码。

实例

简单理解,就是new,就是对类的实例化,创建这个类对应的实际对象,类只是对事物的描述,而实例化就相当于为这个描述新开辟了一块内存,可以改变这块区域里的各种属性(成员变量),当然,也可以实例化多块区域,只是不同的对象而已。

Class

注意这里C大写了,与类概念区分开,在java里,Class是一个实实在在的类,在包 java.lang 下,有这样一个Class.java文件,它跟我们自己定义的类一样,是一个实实在在的类,Class对象就是这个Class类的实例了。在Java里,所有的类的根源都是Object类,而Class也不例外,它是继承自Object的一个特殊的类,它内部可以记录类的成员、接口等信息,也就是在Java里,Class是一个用来表示类的类。(o(∩_∩)o 有点绕啊,抓住关键一点,Class是一个实实在在的类,可以为它创建实例,也就是本文后面提到的Class对象,也看叫做Class实例)。

java提供了下面几种获取到类的Class对象的方法:

1) 利用对象实例调用getClass()方法获取该对象的Class实例;

       2) 使用Class类的静态方法forName("包名+类名"),用类的名字获取一个Class实例

3)运用 类名.class 的方式来获取Class实例;

我们知道java世界是运行在JVM之上的,我们编写的类代码,在经过编译器编译之后,会为每个类生成对应的.class文件,这个就是JVM可以加载执行的字节码。运行时期间,当我们需要实例化任何一个类时,JVM会首先尝试看看在内存中是否有这个类,如果有,那么会直接创建类实例;如果没有,那么就会根据类名去加载这个类,当加载一个类,或者当加载器(class loader)的defineClass()被JVM调用,便会为这个类产生一个Class对象(一个Class类的实例),用来表达这个类,该类的所有实例都共同拥有着这个Class对象,而且是唯一的。

动态代理

image-20240604153546201

image-20240604154121416

image-20240604154154474

查漏:

/t (制表符):打印时补齐字符(1-8位)

/b :退格符

子类方法抛出的异常不能大于父类被重写方法的异常

Ctrl+Alt+t:包围方式

Ctrl+Alt+v:变量声明

Ctrl+p : 提示方法形参

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值