JAVA知识总结

文章目录


我热爱开发
题外话:有些东西很容易忘记,还是记下来好,找的时候也方便些

==此篇博客会一直更新补充 ==

变量名命名规范

POJO类中布尔类型不让用isXxx命名
原因参考链接: 解决当boolean类型的变量命名由is开头时,IDEA自动生成get、set方法的问题.

链接: POJO类中布尔类型为啥不让用isXxx命名.

quartz

mysql和oracle区别(数据库相关知识)

线程

①-进程与线程区别

在这里插入图片描述
在这里插入图片描述

②-并行与并发

在这里插入图片描述

③-JVM启动是单线程还是多线程?

在这里插入图片描述

④-线程调度(Priority)

在这里插入图片描述

⑤-线程控制

⑤-1 线程控制之加入线程

在这里插入图片描述

⑤-2 线程控制之礼让线程

在这里插入图片描述

在这里插入图片描述

⑤-3 线程控制之守护线程

在这里插入图片描述

⑤-4 线程控制之中断线程

在这里插入图片描述
关于中断线程有个知识点可以参看:
https://www.cnblogs.com/maogefff/p/8257293.html

⑥-线程生命周期图

在这里插入图片描述

⑦-多线程的另一种实现方式

在这里插入图片描述

⑧-线程创建两种方式和区别

在这里插入图片描述

⑨-线程安全问题原因和分析

在这里插入图片描述

⑨-1解决线程安全问题方式一Synchronized

在这里插入图片描述

同步的优缺点
优点:解决了多线程的安全问题
缺点:当线程相当多时,因为每个线程都会去判断同步上的 锁,这是很耗费资源的,会降低程序运行效率

更详细的参考文章:
https://www.cnblogs.com/yw-ah/p/5856802.html.

下面这个博主刨析的更透彻
https://www.cnblogs.com/dolphin0520/p/3923737.html.

⑩-同步代码块,同步方法锁 应用和问题

在这里插入图片描述

⑩①-以前线程安全类回顾

在这里插入图片描述

⑩②-JDK5之后的LOCK锁使用

⑩②-1 JDK5之后的LOCK锁使用

在这里插入图片描述

⑩②-2 死锁问题概述

在这里插入图片描述

⑩③-生产消费者模式之等待唤醒机制

在这里插入图片描述

注意:wait()和noitfy()方法要放在synchronized同步代码块里,否则会报error
java.lang.IllegalMonitorStateException

package test.chinasofti.date20200905;

public class GetThread implements Runnable{
	private Student s;
	public GetThread(Student stu) {
		this.s = stu;
	}
	@Override
	public void run() {
		while (true) {
			
			synchronized (s) {
				if (!s.flag) {
					try {
						s.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(s.name + "---" + s.age);
				
				s.flag = false;
				s.notify();
			}
			
		}
		
	}

}

⑩③-1 生产消费者模式之等待唤醒机制(待优化版)

一共四个类
SetThread(生产者)
GetThread(消费者)
Student(学生类)
StudentDemo(测试类)
下面是具体代码块

SetThread(生产者)

package test.chinasofti.date20200905_01;

// 生产者
public class SetThread implements Runnable{
	private Student s;
	int i = 0;
	public SetThread(Student stu) {
		this.s = stu;
	}
	@Override
	public void run() {
		while (true) {
			// 同步代码块待优化处
			synchronized (s) {
				if (s.flag) {
					try {
						s.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				if (i % 2 == 0) {
					s.age = 10;
					s.name = "AAAA";
				} else {
					s.age = 20;
					s.name = "BBBB";
				}
				i++;
				s.flag = true;
				s.notify();
			}
			
		}
		
	}
	
	

}

GetThread(消费者)

package test.chinasofti.date20200905_01;

// 消费者
public class GetThread implements Runnable{
	private Student s;
	public GetThread(Student stu) {
		this.s = stu;
	}
	@Override
	public void run() {
		while (true) {
			// 同步代码块待优化处
			synchronized (s) {
				if (!s.flag) {
					try {
						s.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(s.name + "---" + s.age);
				
				s.flag = false;
				s.notify();
			}
			
		}
		
	}

}

Student(学生类)

package test.chinasofti.date20200905_01;

public class Student {
	int age;
	String name;
	boolean flag;
}

StudentDemo(测试类)

package test.chinasofti.date20200905_01;

public class StudentDemo {

	public static void main(String[] args) {
		Student s = new Student();
		SetThread set = new SetThread(s);
		GetThread get = new GetThread(s);
		
		Thread t = new Thread(set);
		Thread t1 = new Thread(get);
		
		t.start();
		t1.start();

	}

}

⑩③-2 生产消费者模式之等待唤醒机制(优化版)

前提,之前Student(学生类)成员属性都不是私有的,现在要改为私有的

一共四个类
SetThread(生产者)
GetThread(消费者)
Student(学生类)
StudentDemo(测试类)
下面是具体代码块(测试类不需要改动)

SetThread(生产者)

package test.chinasofti.date20200905_01;

// 生产者
public class SetThread implements Runnable{
	private Student s;
	int i = 0;
	public SetThread(Student stu) {
		this.s = stu;
	}
	@Override
	public void run() {
		while (true) {
			// 同步代码块待优化处
//			synchronized (s) {
//				if (s.flag) {
//					try {
//						s.wait();
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
//				}
				if (i % 2 == 0) {
//					s.age = 10;
//					s.name = "AAAA";
					s.setStudent("AAAA", 10);
				} else {
//					s.age = 20;
//					s.name = "BBBB";
					s.setStudent("BBBB", 10);
				}
				i++;
//				s.flag = true;
//				s.notify();
			}
			
		}
		
//	}

}

GetThread(消费者)

package test.chinasofti.date20200905_01;

// 消费者
public class GetThread implements Runnable{
	private Student s;
	public GetThread(Student stu) {
		this.s = stu;
	}
	@Override
	public void run() {
		while (true) {
			// 同步代码块待优化处
//			synchronized (s) {
//				if (!s.flag) {
//					try {
//						s.wait();
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
//				}
//				System.out.println(s.name + "---" + s.age);
//				
//				s.flag = false;
//				s.notify();
//			}
			s.getStudent();
		}
		
	}

}

Student(学生类)

package test.chinasofti.date20200905_01;

public class Student {
	private int age;
	private String name;
	private boolean flag;// 默认false
	
	// 表示生产
	public synchronized void setStudent (String name,int age) {
		// 如果生产了,就等待
		if (this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// 如果没生产,就生产
		this.name = name;
		this.age = age;
		
		this.notify();
		this.flag = true;
	}
	
	// 表示消费
	public synchronized void getStudent () {
		// 如果没有生产品,就等待,现在没法消费
		if (!this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// 如果有生产品,就消费
		System.out.println(this.name + "---" + this.age);
		
		this.notify();
		this.flag = false;
	}
}

StudentDemo(测试类)

package test.chinasofti.date20200905_01;

public class StudentDemo {

	public static void main(String[] args) {
		Student s = new Student();
		SetThread set = new SetThread(s);
		GetThread get = new GetThread(s);
		
		Thread t = new Thread(set);
		Thread t1 = new Thread(get);
		
		t.start();
		t1.start();

	}

}

总结:
在这里插入图片描述

⑩④-线程的状态转换图和常见执行情况

在这里插入图片描述

⑩⑤-线程组的概述和应用

在这里插入图片描述

⑩⑥-线程池的概述和应用

在这里插入图片描述

⑩⑦-匿名内部类的方式实现多线程

在这里插入图片描述
附:练习代码

package test.chinasofti.date20200906;

public class jobSeeker20200906_02 {

	public static void main(String[] args) {
		//匿名内部类方式实现多线程方式
		// 方式1 继承thread类实现多线程
		new Thread() {
			@Override
			public void run() {
				for (int i = 0;i<100;i++) {
					System.out.println(Thread.currentThread().getName()+ ":" + i);
				}
			}
		}.start();
		
		// 方式2 实现runnable接口,创建多线程并启动
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0;i<100;i++) {
					System.out.println("hello"+ ":" + i);
				}		
			}
		}){
		}.start();
				
		// 方式3 实现runnable接口,创建多线程并启动,没意义,可以在方法体再写run方法
		// 这里会输出 word+i
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 0;i<100;i++) {
					System.out.println("hello"+ ":" + i);
				}		
			}
		}){
			@Override
			public void run() {
				for (int i = 0;i<100;i++) {
					System.out.println("word"+ ":" + i);
				}
			}
		}.start();

	}

}

⑩⑧-定时器的概述和使用

在这里插入图片描述

Java 值传递和引用传递

转载:链接: 值传递和引用传递.
补充:string:具有不可变。是特殊的引用类型,其作用跟基本类型一样,传递后不相关。

Ajax

①-Ajax的原理

Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。

②-ajax请求(五步骤)

①创建ajax对象 var xhr=new XMLHttpRequest()

②建立一个http连接 xhr.open(‘get’,url,true);

③发送一个http请求 xhr.send(null);

④给ajax状态绑定一个回调函数 xhr.onreadystatechange=function(){};

⑤判断ajax的状态是否等于4,就做相应的业务逻辑 xhr.readyState==4 接收字符串xhr.responseText

转载于:
链接: 史上最详细的ajax教程.

Spring

❶ - C语言中文网部分对Spring的理解

链接: spring自动注入是单例还是多例?单例如何注入多例?.

链接: Spring中单例Bean是线程安全的吗.

❶ - 1 Bean生命周期(singleton 和 prototype)

关于Bean生命周期:
Spring 根据 Bean 的作用域来选择管理方式。对于 singleton 作用域的 Bean,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁;而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。

那如何验证呢?

首先,你需要看一篇基础知识,大约需要5分钟,然后我们做个测试,答案大家自然就能明白Bean的生命周期。

链接: Spring Bean生命周期.

首先我们先测试单例模式singleton

代码如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="helloWorld" class="net.biancheng.HelloWorld" scope="singleton"
    	init-method="init" destroy-method="destroy">
        <property name="message" value="Hello World!" />
    </bean>

</beans>
package net.biancheng;

public class HelloWorld {
    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public void getMessage() {
        System.out.println("message : " + message);
    }
    
    private void init() {
		System.out.println("测试xml配置的初始化方法");
	}
    
    private void destroy() {
    	System.out.println("测试xml配置的销毁方法");
	}
}
package net.biancheng;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
    	//Spring实例
//        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
    	AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
        obj.setMessage("对象A");//注意1-getBean两次对象
        obj.getMessage();
        context.registerShutdownHook();//注意2-只调用一次销毁
        
        //测试单例模式和原型模式
        HelloWorld obj2 = (HelloWorld) context.getBean("helloWorld");
        obj2.getMessage();
    }
}
测试xml配置的初始化方法
message : 对象A
message : 对象A
测试xml配置的销毁方法

所以,验证了:对于 singleton 作用域的 Bean,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁;

Spring 知道Bean 所有生命周期,所以它调用了初始和销毁方法,又因为验证了单例是容器内只存在一个对象,所以只存在调用一次初始化方法,并且销毁方法最后才调用。

最后我们测试原型模式prototype

我们只改动xml配置


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="helloWorld" class="net.biancheng.HelloWorld" scope="prototype"
    	init-method="init" destroy-method="destroy">
        <property name="message" value="Hello World!" />
    </bean>

</beans>

var foo = 'bar';
测试xml配置的初始化方法
message : 对象A
测试xml配置的初始化方法
message : Hello World!

所以,验证了:对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。

Spring 只负责创建,所以它调用了初始而不会调用销毁方法,又同时验证了原型模式每次通过 Spring 容器获取 Bean 时,容器都会创建一个 Bean 实例,所以会调用两次初始化方法。

①-Spring注解

①-1 注解 @Qualifier 详细解析

链接: Spring 注解 @Qualifier 详细解析.

①-2 Spring系列之Spring常用注解总结

链接: Spring系列之Spring常用注解总结.

①-3 @Autowired注入时到底是根据byType还是byName

链接: 一篇文章告诉你spring中的@Autowired注入时到底是根据byType还是byName.

当然也有人不同意见:

链接: 都0202年了还在说spring@Autowired是byType注入的?.

①-4 @Scope(“prototype”)的正确用法——解决Bean的多例问题

转载:
链接: @Scope(“prototype”)的正确用法——解决Bean的多例问题.

对此感想:每个注解都不是看起来那么简单,有些东西,开发可能用不到就真的不知道。

①-5 15个Spring的核心注释示例

链接: 15个Spring的核心注释示例.

总结:全面,但不是很具体

②-注入一个bean?spring是如何实现的?

1-先考虑使用xml文件定义bean的情况。

spring解析bean加载到容器当中主要有以下几步:

1-在xml文件里定义bean的信息
2-使用dom4j技术解析xml文件->拿到类名->使用反射技术创建类对应的class对象
3-使用反射技术-根据类对象创建实例对象
4-设计模式的工厂模式

从整体来看,解析和创建类对象的代码是放在一个统一的地方管理的,在这里使用了工厂模式。

2-不使用xml,而使用注解@Autowire注入一个bean?spring是如何实现的?

1-利用反射机制获取一个类的Class对象
2-通过这个class对象可以去获取他的每一个字段Field
3-Field类提供了方法getDeclaredAnnotations来获取这个一个字段的所有注解

具体可参照贴子:
链接: spring重点知识.

③-Spring学习 Bean配置的三种方式(XML、注解、Java类)介绍与对比

链接: Bean配置的三种方式(XML、注解、Java类)介绍与对比.

设计模式(23)

①-模板设计模式

具体可以参照别人的贴子:

链接: 模板设计模式.
在这里插入图片描述
总结:感觉这个应该蛮常用的

②-装饰模式

举例: Scanner sc = new Scanner (System.in);
装饰模式常用在IO流

③-简单工厂模式

④-工厂方法模式

⑤-单例模式(饿汉,饥汉式)

Java 读取配置文件

在这里插入图片描述
在这里插入图片描述

Mybatis

①-Mybatis 中$和#

参照转载的一篇文章:
链接: Mybatis 中$和#.

这个是跟sql注入安全有关系的首先介绍下sql注入攻击:

sql注入攻击
通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。通俗地讲,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

关于sql注入攻击,可以参考下面别人的贴子:
链接1: SQL注入其实很简单,别一不留神就被利用了.

链接2: 利用SQL注入漏洞登录后台的实现方法.

个人感悟

之前做项目时前台单项目check和后台单项目check都会存在,那时候不理解为什么前台明明做了check,为什么后端仍要做同样的check呢?现在看了上面的sql注入攻击,有点理解了。如果通过特殊手段绕过了前端check,那么后端是有机会拦截到的。

有些事情,你可能一时无法理解,但是努力不会白费

反射

①-java反射机制

java反射机制就是在运行状态下,对于任意一个类,都能知道类中任意的属性和方法;对于任意一个对象,都能调用它的任意方法和属性,这种动态获取信息和动态调用对象方法的功能就是Java的反射机制。

②-获取Class对象的三种方式

①-获取Class对象的三种方式:
在这里插入图片描述
开发使用:

③-通过反射获取构造方法(无参,有参,私有)

②-1通过反射获取无参构造方法并输出

在这里插入图片描述
②-2通过反射获取带参构造方法并输出

在这里插入图片描述
②-3通过反射获取私有构造方法并输出
(这里注意重点代码)

Constructor cc3 = c3.getDeclaredConstructor(String.class);
cc3.setAccessible(true);
在这里插入图片描述

④-通过反射获取成员变量并使用

通过反射获取成员变量并使用

在这里插入图片描述

⑤-通过反射调用无参无返回值方法并使用

在这里插入图片描述
下面是练习例子:

package test.chinasofti.date20200815;

public class Student {

	public String name;
	
	String sex;
	
	private int age;
	
	public Student () {
		
	}
	
	public Student (String name,int age) {
			this.age = age;
			this.name = name;
		}
	
	private Student (String name) {
			this.name = name;
	}
	
	public void show ( ) {
		System.out.println("show");
	}
	
	public void showParameter (String s ) {
		System.out.println("参数:" + s);
	}
	
	public String returnShow (String s ) {
		return s;
	}
	
	private String returnPrivateShow (String s ) {
		return s;
	}
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "-" + "name:" + this.name + "   age:" + this.age + "  sex:" +this.sex;
	}
}


package test.chinasofti.date20200815;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class jobSeeker20200804_15_04 {

	public static void main(String[] args) throws Exception {
		// 通过反射调用无参无返回值方法show
		// 1-获取class对象
		Class c1 = Class.forName("test.chinasofti.date20200815.Student");
		// 2-取得构造器对象
		Constructor cc1 = c1.getConstructor();
		// 3-通过构造器创建实例
		Object obj = cc1.newInstance();
		// 4-获取方法
		Method m1 = c1.getMethod("show");
		// 5-用第三步的实例调用方法
		m1.invoke(obj);

		// 通过反射调用带参无返回值方法showParameter
		Method m2 = c1.getMethod("showParameter", String.class);
		m2.invoke(obj, "haha");
		
		// 通过反射调用带参带返回值方法returnShow
		Method m3 = c1.getMethod("returnShow", String.class);
		Object obj2 = m3.invoke(obj, "lala");
		System.out.println(obj2);
		
		// 通过反射调用私有方法returnPrivateShow
		Method m4 = c1.getDeclaredMethod("returnPrivateShow", String.class);
		m4.setAccessible(true);
		Object obj3 = m4.invoke(obj, "wawa");
		System.out.println(obj3);
	}

}

⑥-通过反射越过泛型检查

在这里插入图片描述
自己的练习

package test.chinasofti.date20200817;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class jobSeeker20200804_17_02 {

	public static void main(String[] args) throws Exception {
		// 通过反射越过泛型检查
		ArrayList<String> a = new ArrayList<String>();
		
//		a.add(1); //这么做会error
		// 接下来用反射实现上述操作
		Class c = a.getClass();
		Method m = c.getMethod("add", Object.class);
		m.invoke(a, 1);
		
		System.out.println(a);

	}

}

类初始化时机

1-创建类的实例
2-访问类的静态变量,或者为静态变量赋值
3-调用类的静态方法
4-使用反射强制创建类或者接口的Class对象
5-初始化类的子类
6-直接使用java.exe运行某个主类

用过的MySQL图形化管理工具

①-PHPMyAdmin

②-Navicat

③-MySQL Workbench

JDK5新特性

在这里插入图片描述

①-增强for循环

首先是总结点,然后我们再具体分析

1.首先增强for循环和iterator遍历的效果是一样的,也就说增强for循环的内部也就是调用iteratoer实现的,

但是增强for循环有些缺点,例如不能在增强循环里动态的删除集合内容(导致并发修改异常)。不能获取下标等。

2.ArrayList由于使用数组实现,因此下标明确,最好使用普通循环。

3.而对于LinkedList 由于获取一个元素,要从头开始向后找,因此建议使用增强for循环,也就是iterator。(前三点转载)

对于前三点可以参照一篇文章链接: link.

4.增强for循环目标不能是null,但是可以空对象。(这点普通for循环一样)

换言之:当list为空的时候会报空指针异常,但是如果是一个空对象的时候会跳过for循环,不进行for循环中的任何的操作.

具体解释:增强for循环对于集合的遍历实际走的是迭代器的方式(对于数组的遍历这是走的普通的for循环方式), 在进行strings.iterator()时,如果strings为null,就会出现空指针异常,如果strings为空集合,则在判断hasNext()为false,程序不再往下进行,不会出现异常。

题外话:遍历其实有三种,当然说两种也对
在这里插入图片描述
在这里插入图片描述

②-枚举

关于枚举,有个贴子论述的不错
链接: 浅谈在Java开发中的枚举的作用和用法.

下面是自己练习的代码

package test.chinasofti.date20200818;

public enum EnumClass {
	// 通过enum实现枚举类
	ADD("add"){
		@Override
		public void show() {
			System.out.println("show add");			
		}	
	},DELETE("delete"){
		@Override
		public void show() {
			System.out.println("show delete");			
		}		
	};
	
	private String name;
	private EnumClass (String s) {
		this.name = s;
	}
	public String getName() {
		return this.name;
	}
	
	public abstract void show ();

}


package test.chinasofti.date20200818;

public class jobSeeker20200804_18_02 {

	public static void main(String[] args) {
		// 1
		EnumClass en = EnumClass.ADD;
		System.out.println(en);
		
		System.out.println("----------------");
		
		// 2
		EnumClass en2 = EnumClass.ADD;
		System.out.println(en2);
		System.out.println(en2.getName());
		
		System.out.println("----------------");
		
		// 3
		EnumClass en3 = EnumClass.ADD;
		System.out.println(en3);
		en3.show();
		

	}

}

输出结果:

ADD
----------------
ADD
add
----------------
ADD
show add

数据结构

八大数据结构分类:

1、数组
2、栈
3、队列
4、链表
5、树
6、散列表
7、堆
8、图

排序相关知识

package test.chinasofti;

import java.util.Arrays;
import java.util.Comparator;

public class jobSeeker20200804 {
	public static void main(String[] args) {
		Integer[] numberArray = {2,4,3,8,29,0,-1,4,7};
//		arraySort(numberArray);
//		System.out.println(Arrays.toString(numberArray));
		
//		arraySelectSort(numberArray);
//		System.out.println(Arrays.toString(numberArray));
		
//		arrayNuSort(numberArray);
//		System.out.println(Arrays.toString(numberArray));
		
		Comparator cp = new MyComparatorl();
		Arrays.sort(numberArray,cp);
		System.out.println(Arrays.toString(numberArray));
	}
	
	
	public static void arraySort(int [] array) {
		// 冒泡排序
		// 相邻元素两两比较,大的往后放,第一次完毕后,最大值出现最大索引处。同理,其他位置也是如此
		for(int x = 0; x <array.length -1; x ++) {
			for(int y = 0; y <array.length -1 -x; y++) {
				if(array[y] > array[y+1]) {
					int temp = array[y];
					array[y] = array[y+1];
					array[y+1] = temp;
				}
			}
		}
	}
	
	public static void arraySelectSort(int [] array) {
		// 选择排序
		// 把0索引元素和1索引以后元素进行比较。第一次结束最小值在最小索引处。同理,其他位置也是如此
		for(int x = 0; x <array.length -1; x++) {
			for(int y = x+1; y <array.length; y++) {
				if(array[x] > array[y]) {
					int temp = array[y];
					array[y] = array[x];
					array[x] = temp;
				}
			}
		}
	}
	
	public static void arrayNuSort(int [] array) {
		// 反转排序
		for(int x = 0; x <array.length/2; x++) {
			int temp = array[x];
			array[x] = array[array.length -x -1];
			array[array.length -x -1] = temp;
		}
	}
}

class MyComparatorl implements Comparator<Integer>{

	// 自定义排序
	@Override
	public int compare(Integer o1, Integer o2) {
		// TODO Auto-generated method stub
		return o1-o2;
	}
	
}


最重要的就是自定义排序,自定义排序还可以这么用

package test.chinasofti;
 
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
 
public class cc {
    	   public static void main(String[] args) {
    		           /*注意,要想改变默认的排列顺序,不能使用基本类型(int,double, char)
    		           而要使用它们对应的类*/
    		           String[] a = {"a","ss","dddd","aa"};
    		           //定义一个自定义类MyComparator的对象
    		           Comparator cmp = new MyComparator();
    		           Arrays.sort(a,cmp);
    		           for(String arr:a) {
    		               System.out.print(arr + " ");
    		           }
    		       }
    		   }
    		   //实现Comparator接口
    		   class MyComparator implements Comparator<String>{
    		      @Override
    		       public int compare(String o1, String o2) {
    		        /*如果o1小于o2,我们就返回正值,如果o1大于o2我们就返回负值,
    		         这样颠倒一下,就可以实现降序排序了,反之即可自定义升序排序了*/
    		       return o1.length()
    		    		   -o2.length();    
       }
    	
  }

JAVA的API错误方法命名

arraycopy

不符合驼峰式命名规则

浮点数的加减乘除

浮点数的加减乘除要用 BigDecimal

时间日期转换

package test.chinasofti;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.crypto.Data;

public class jobSeeker20200804_06 {
	public static void main(String[] args) throws ParseException {
		Date d = new Date();
		// Date 转 String
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd HHmmss"+"");
		String s = sdf.format(d);
		System.out.println(s);
		
		// String 转Date
		String ss = "2020年08月06 111608";
		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd HHmmss"+"");
		Date d2 = sdf2.parse(ss);
		System.out.println(d2);
	}
}

集合知识

①-集合的专属遍历_迭代器Iterator

package test.chinasofti;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class jobSeeker20200804_07 {

	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("1000");
		System.out.println(Arrays.toString(list.toArray()));
		
		int[] array = {1,5,8};
		System.out.println(Arrays.toString(array));
		
		Collection c = new ArrayList();
		c.add("ss");
		c.add(12L);
		System.out.println("--------集合的专属遍历_迭代器Iterator-------------");
		Iterator it = c.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
		
		System.out.println(Arrays.toString(c.toArray()));
	}

}

注意事项1: 不要用下面方式输出

【两个next()会导致取出内容不正确,还会报错NoSuchElementException】

【因为相当于走了两次next】

System.out.println(it.next().getName() + "---" + it.next().getAge());

注意事项2: 使用迭代器时有时候会出现并发修改异常
ConcurrentModificationException

package test.chinasofti;

import java.util.List;
import java.util.ListIterator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

public class jobSeeker20200804_09 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List list = new ArrayList();
		list.add("1");
		Iterator it = list.iterator();
		while (it.hasNext()) {
			if (it.next().equals("1")) {
				// ConcurrentModificationException
				// 产生原因:迭代器依赖于集合存在的,集合添加元素,迭代器却不知道,所以报错,这个错叫并发修改异常
				// 其实这个问题描述的是:迭代器遍历元素时候,通过集合是不能修改元素的
				list.add("2");
			}
		}
		
		// 解决方案1 迭代器迭代元素,迭代器修改元素
		// 使用ListIterator,让迭代器修改元素,不过这种方式追加的元素是在迭代元素后面
//		ListIterator it = list.listIterator();
//		while (it.hasNext()) {
//			String s = (String)it.next();
//			if (s.equals("1")) {
//				it.add("2");
//			}
//			System.out.println(s);
//		}
		
		// 解决方案2 集合迭代元素,集合修改元素
		// 这种方式追加的元素是在最后
//		for (int i = 0; i < list.size(); i ++) {
//			if (list.get(i).equals("1")) {
//				list.add("2");
//			}
//		}
		System.out.println(Arrays.toString(list.toArray()));
	}

}

②-List集合注意点

package test.chinasofti;

import java.util.ArrayList;
import java.util.List;

public class jobSeeker20200804_08 {

	public static void main(String[] args) {
		List list = new ArrayList();
		list.add(1);
		
		// 第一种情况 OK
		list.add(1,2);
		
		// 第二种情况 ERROR  java.lang.IndexOutOfBoundsException
		// 注意添加时,最大位置是集合索引最大值加1,像这个例子,最大索引值是0,所以add功能第一个参数最大值是1
		list.add(2,2);

	}

}

③-List三个子类特点

ArrayList :底层数据结构是数组,查询快,增删慢
不是同步的,线程不安全,效率高

Vector:底层数据结构是数组,查询快,增删慢
是同步的,线程安全,效率低

LinkedList:底层数据结构是链表,查询慢,增删快
不是同步的,线程不安全,效率高

补一张很有意思的图
在这里插入图片描述

④-泛型高级之通配符

package test.chinasofti.date20200812;

import java.util.ArrayList;
import java.util.Collection;

public class jobSeeker20200804_12_02 {

	public static void main(String[] args) {
		
		// ?表示任意类型都是可以的
		Collection<?> c = new ArrayList<Object>();
		Collection<?> c1 = new ArrayList<Animial>();
		Collection<?> c2 = new ArrayList<Dog>();
		
		// ? extends E 向下限定,它及其子类
		Collection<? extends Animial> c3 = new ArrayList<Object>(); //ERROR
		Collection<? extends Animial> c4 = new ArrayList<Animial>();
		Collection<? extends Animial> c5 = new ArrayList<Dog>();
		
		// ? super E 向上限定,它及其父类
		Collection<? super Animial> c6 = new ArrayList<Object>(); 
		Collection<? super Animial> c7 = new ArrayList<Animial>();
		Collection<? super Animial> c8 = new ArrayList<Dog>(); //ERROR
		
		// 泛型如果明确写的话,必须前后一致
		Collection<Object> c9 = new ArrayList<Object>();
		Collection<Object> c10 = new ArrayList<Animial>(); //ERROR
		Collection<Object> c11 = new ArrayList<Dog>(); //ERROR
	}

}

class Animial {
	
}

class Dog extends Animial {
	
}

⑤-Set集合

概述

一个不包含重复元素的collection

⑤-1 HashSet集合

在这里插入图片描述
HashSet保证元素唯一性的原因
在这里插入图片描述

⑤-2 LinkedHashSet集合

在这里插入图片描述
下面是练习,很容易看出LinkedHashSet的有序和HashSet的无序对比

HashSet的无序

package test.chinasofti.date20200914;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class jobSeeker20200914_01 {

	public static void main(String[] args) {
		// Set集合遍历自定义对象
		Set<Student> hs = new HashSet<Student>();//只有这行代码变
		Student s = new Student("1A",1);
		Student s1 = new Student("3B",2);
		Student s2 = new Student("5C",3);
		Student s3 = new Student("9D",1);
		Student s4 = new Student("99A",1);
		Student s5 = new Student("999E",1);
		Student s6 = new Student("9999F",1);
		Student s7 = new Student("9999G",1);
		Student s8 = new Student("999H",1);
		Student s9 = new Student("9I",1);
		Student s10 = new Student("9I",1);
		
		hs.add(s);
		hs.add(s1);
		hs.add(s2);
		hs.add(s3);
		hs.add(s4);
		hs.add(s5);
		hs.add(s6);
		hs.add(s7);
		hs.add(s8);
		hs.add(s9);
		hs.add(s10);
		
		for (Student result : hs) {
			System.out.println(result);
		}
	}

}


Student [age=1, name=1A]
Student [age=1, name=9I]
Student [age=1, name=99A]
Student [age=1, name=999H]
Student [age=1, name=999E]
Student [age=1, name=9999F]
Student [age=1, name=9999G]
Student [age=1, name=9D]
Student [age=3, name=5C]
Student [age=2, name=3B]

LinkedHashSet的有序

package test.chinasofti.date20200914;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class jobSeeker20200914_01 {

	public static void main(String[] args) {
		// Set集合遍历自定义对象
		Set<Student> hs = new LinkedHashSet<Student>(); //只有这行代码变
		Student s = new Student("1A",1);
		Student s1 = new Student("3B",2);
		Student s2 = new Student("5C",3);
		Student s3 = new Student("9D",1);
		Student s4 = new Student("99A",1);
		Student s5 = new Student("999E",1);
		Student s6 = new Student("9999F",1);
		Student s7 = new Student("9999G",1);
		Student s8 = new Student("999H",1);
		Student s9 = new Student("9I",1);
		Student s10 = new Student("9I",1);
		
		hs.add(s);
		hs.add(s1);
		hs.add(s2);
		hs.add(s3);
		hs.add(s4);
		hs.add(s5);
		hs.add(s6);
		hs.add(s7);
		hs.add(s8);
		hs.add(s9);
		hs.add(s10);
		
		for (Student result : hs) {
			System.out.println(result);
		}
	}

}


Student [age=1, name=1A]
Student [age=2, name=3B]
Student [age=3, name=5C]
Student [age=1, name=9D]
Student [age=1, name=99A]
Student [age=1, name=999E]
Student [age=1, name=9999F]
Student [age=1, name=9999G]
Student [age=1, name=999H]
Student [age=1, name=9I]

⑤-3 TreeSet集合

在这里插入图片描述

⑤-3-1 TreeSet集合自然排序

TreeSet集合保证元素自然排序源码得知:真正的比较是依赖于元素的compareTo方法,而这个方法是定义在Comparable里面的,所以你要重写此方法,就必须先实现Comparable接口。这个接口表示的就是自然排序

在这里插入图片描述

TreeSet集合保证元素自然排序和唯一性图解

在这里插入图片描述

实现Comparable接口,自然排序例子

在这里插入图片描述

⑤-3-2 TreeSet集合比较器排序

方式一

在这里插入图片描述

方式二,匿名内部类

在这里插入图片描述

⑤-3-3 TreeSet集合排序总结

在这里插入图片描述

⑥ -集合总结

在这里插入图片描述

在这里插入图片描述

⑦ -Map

⑦ - 1 Map集合概述和特点

在这里插入图片描述

在这里插入图片描述

⑦ - 2 Map遍历
package test.chinasofti.date20200901;

import java.util.HashMap;
import java.util.Map;

public class jobSeeker20200901_01 {

	public static void main(String[] args) {
		Map<String,String> m = new HashMap<String,String>();
		m.put("1", "value1");
		m.put("3", "value3");
		m.put("2", "value2");
		
		m.remove("1");
		
		// 循环1 通过Map.keySet遍历key和value:
		System.out.println("通过Map.keySet遍历key和value:");
		for (String key : m.keySet()) {
			System.out.println("key: " + key + " value: " + m.get(key));
		}
		
		System.out.println("通过Map.entrySet遍历key和value");
		for (Map.Entry<String, String> entry : m.entrySet()) {
			System.out.println("key: " + entry.getKey() + " value: " + entry.getValue());
		}

	}

}

在这里插入图片描述

⑦ - 3 LinkedHashMap遍历

在这里插入图片描述

⑦ - 4 TreeMap遍历

在这里插入图片描述

⑦ - 5 Hashtable与HashMap

注意:Hashtable中t是小写,简单的说Hashtable是用来代替HashMap的,就像ArrayList代替Vector

在这里插入图片描述

在这里插入图片描述

⑧ Collections工具类

在这里插入图片描述

对Collections.binarySearch()的补充:
如果搜索键包含在列表中,则返回搜索键的索引;
否则返回 (-(插入点) - 1)。

插入点 被定义为将键插入列表的那一点:

即第一个大于此键的元素索引;如果列表中的所有元素都小于指定的键,则为 list.size()。注意,这保证了当且仅当此键被找到时,返回的值将 >= 0。

⑧ -1 Collections工具类排序用法之ArrayList存储自定义对象并排序

两种方式:1-自然排序
2-比较器排序
再加上去除重复元素功能,ArrayList是能代替Set的

在这里插入图片描述

IO流

①-异常处理(IO流前提1)

① - 1 throws和throw区别

在这里插入图片描述

① - 2 finally关键字特点

在这里插入图片描述

① - 3 finally,final,finalize区别

在这里插入图片描述

① - 4 finally和return的关系

试想下面结果是多少?
在这里插入图片描述

在这里插入图片描述

很奇怪对不对,大部分人应该觉得是40吧。
我们来debug
return之前是30没问题
在这里插入图片描述
然后进来

在这里插入图片描述
a = 40; 这行代码走完后

在这里插入图片描述
return,然后走到main方法

在这里插入图片描述
控制台输出30

在这里插入图片描述
为什么会这样呢?这里给个解释:

在这里插入图片描述
因此,对于某个面试题来说,答案是说在前,更准确是中间

在这里插入图片描述

① - 5 异常注意事项

在这里插入图片描述

② File类(IO流前提2)

② - 1 File类的创建(三个方法)

注意:要想在某个目录下创建东西,则该目录必须首先存在!如果存在创建的目录则不会再次创建,会返回false
在这里插入图片描述
下面介绍第三个方法用于打破上面的制约:要想在某个目录下创建东西,则该目录必须首先存在!
在这里插入图片描述
但是注意,这是创建文件夹的方法,不是创建文件。
总结如下:

在这里插入图片描述

那如果你创建文件或者文件夹时候忘记写了盘路径,默认是你项目路径下,如下面的例子。a.txt在day19_File路径下,并不是所谓的默认C盘之类的

在这里插入图片描述

② - 2 File类的删除

在这里插入图片描述

② - 3 File类的重命名

在这里插入图片描述

② - 4 File类的判断功能

在这里插入图片描述

② - 5 File类的获取功能

在这里插入图片描述

② - 6 File类的高级获取功能

在这里插入图片描述

③ 递归

在这里插入图片描述

④ IO流描述

在这里插入图片描述

④ - 1 IO流分类

在这里插入图片描述

一个例子

在这里插入图片描述

IO流常用基类

在这里插入图片描述

④ - 2 FileOutPutStream写出数据

在java中,为什么input是读取而output是写入?这不符合直觉。
输入输出都是针对内存。input,输入到内存。也就是从其他数据源取数据,然后输入到内存。显然这就是读文件到内存。输出同理。

在这里插入图片描述
注意最后关闭资源

为什么要释放资源呢

在这里插入图片描述

最后,自己写的例子

在这里插入图片描述

FileOutPutStream的三个write方法
在这里插入图片描述

FileOutPutStream写出数据的追加和换行

在这里插入图片描述

④ - 3 FileItPutStream读取数据

在这里插入图片描述
读取数据方式2
在这里插入图片描述

④ - 4 计算机是如何识别把两个字节拼成中文的?

在这里插入图片描述

④ - 5 BufferedOutPutStream写出数据

在这里插入图片描述

④ - 6 BufferedInPutStream读取数据

在这里插入图片描述

④ - 7 转换流出现的原因和格式

在这里插入图片描述

编码表概述和常见编码表

在这里插入图片描述

转换流OutputStreamWriter的使用

在这里插入图片描述

转换流InputStreamReader的使用

在这里插入图片描述

④ - 8 close和flush区别

在这里插入图片描述

④ - 9 在close()之前使用flush()是否有必要???

这是一个很重要的问题,我查阅了网上很多资料,也问过一些人,但是得到的回答都不太一样。最终,我觉得安全起见,还是有必要的,尽管有的时候确实多余。下面给出一个参考链接以及里面相对应的不错的观点

链接: 在 close() 之前使用 flush().

下面是对应的不错的观点

《1》

在这里插入图片描述

《2》

在这里插入图片描述

《3》

在这里插入图片描述

④ - 10 转换流的简化写法

在这里插入图片描述

filewriter继承outputstreamwriter

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

④ - 11 字符缓冲流

在这里插入图片描述

这里只举了BufferWriter例子
在这里插入图片描述

字符缓冲流的特殊功能

在这里插入图片描述
在这里插入图片描述

字符缓冲流复制文本特殊案例(掌握)newLine()方式

在这里插入图片描述

④ - 12 IO流总结

在这里插入图片描述

复制文本文件的5中种方式

在这里插入图片描述

第一种

在这里插入图片描述

第二种
在这里插入图片描述

第三种
在这里插入图片描述

第四种
在这里插入图片描述

第五种(推荐)
在这里插入图片描述
练习例子1(将多级文件夹复制到指定位置)

package test.chinasofti.date20210623;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class FileCopy {

	public static void main(String[] args) throws IOException {
		//将多级文件夹复制到指定位置
		//source: E:\demo
		//target: E:\demoTarget
		File source = new File("E:\\demo");
		File target = new File("E:\\demoTarget");
		
		if (!target.exists()) {
			target.mkdirs();
		}
		
		isDirectoryOrFile(source, target);	//主要判断逻辑
	}

	private static void isDirectoryOrFile(File source, File target) throws IOException {
		File[] sources = source.listFiles();
		for (File sourceFile : sources) {
			//true表示文件夹
			if (sourceFile.isDirectory()) {
				File file = new File(target, sourceFile.getName());
				if (!file.exists()) {
					file.mkdirs();
				}
				isDirectoryOrFile(sourceFile, file);
			} else {
				File file  = new File(target, sourceFile.getName());
				copyFiles(sourceFile, file);
			}
		}
		
	}

	private static void copyFiles(File source, File target) throws IOException {
		
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target));
		
		byte[] byt = new byte[1024] ;
		int flag = 0;
		while ((flag = bis.read(byt)) != -1) {
			bos.write(byt, 0, flag);
		}
		bos.close();
		bis.close();
	}

}

再次总结下
在这里插入图片描述

在这里插入图片描述

④ - 13 其他流(了解)
④ - 13 - 1 操作基本数据流(了解)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

示例
在这里插入图片描述

④ - 13 - 2 内存操作流(了解)

在这里插入图片描述

close方法不需要,这是API里说明的,而且通过查看源码可以发现close方法里什么都没有

在这里插入图片描述

在这里插入图片描述

④ - 13 - 3 打印流(了解)

在这里插入图片描述

上述最后一条【可以操作文件流】是因为查看API可以得知其构造函数里可以传入File和String
在这里插入图片描述

同样 FileInputStream亦【可以操作文件流】是因为查看API可以得知其构造函数里可以传入File和String
在这里插入图片描述

同样 FileReader亦【可以操作文件流】是因为查看API可以得知其构造函数里可以传入File和String

在这里插入图片描述

然而!!!
BufferedReader不可以【可以操作文件流】是因为查看API可以得知其构造函数里可以【不可以】传入File和String

在这里插入图片描述

所以就有了下面的总结关于【可以直接操作文本文件流】
这是打印流一大特点

在这里插入图片描述

关于打印流一大特点【自动刷新】需要满足两个条件
1-构造函数需要传入boolean变量;

在这里插入图片描述

2-需要特定的方法启动刷新
在这里插入图片描述

关于打印流一大特点【自动刷新】例子,
这时候close方法就不需要了,而且数据还实现了换行

在这里插入图片描述

println就等价于之前的输出/换行/刷新

在这里插入图片描述

!!!注意这时候最后的close虽然省略掉输出效果一样,但是流并没有关闭,所以close还是要加的!!!

④ - 13 - 4 标准输入输出流(了解)

在这里插入图片描述

在这里插入图片描述

④ - 13 - 5 随机访问流(了解)

写入数据例子

在这里插入图片描述

读取数据例子

在这里插入图片描述

总结:随机流特点能读能写,而且能从任意位置开始读写

④ - 13 - 6 合并流(了解)

在这里插入图片描述

合并流读取两个文件的内容并复制到一个文件
在这里插入图片描述

合并流读取多个文件的内容并复制到一个文件,注意这里需要用到vector
在这里插入图片描述

④ - 13 - 7 序列化流与反序列化流(了解)

在这里插入图片描述

例子(学生类实现了序列化接口)
在这里插入图片描述

在这里插入图片描述

!!!实现序列化接口时需要注意的事项!!!

在这里插入图片描述

如果没有生成序列化id,序列化数据后,再次修改类文件,读取数据就会出现下面这个异常

在这里插入图片描述

另外,使用关键字trainsient可以声明不需要被序列化的变量
在这里插入图片描述

序列化写入学生对象数据时年龄时27,然后对age使用了关键字trainsient,反序列化读取时age就不是27
在这里插入图片描述

④ - 13 - 8 Properties集合(了解)

在这里插入图片描述

API描述:

在这里插入图片描述

作为Map集合的使用

在这里插入图片描述

特殊功能使用

在这里插入图片描述

load和store方法

在这里插入图片描述

与此关联的,有个Properties 类的详细使用,请参考下面链接
链接: Properties 类的详细使用.

④ - 13 - 9 NIO介绍和JDK7下的NIO案例(了解)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

GUI(图形用户界面)

① - GUI(图形用户界面)介绍

在这里插入图片描述

② - JAVA awt与swing包的概述

在这里插入图片描述

③ - GUI组件中继承图

在这里插入图片描述

④ - GUI(窗体案例)

在这里插入图片描述

在这里插入图片描述

⑤ - GUI(窗体关闭案例)

在这里插入图片描述
实现匿名内部类的下面这个方法

@Override
			public void windowClosing(WindowEvent e) {//窗体关闭
				System.exit(0);			
			}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值