Java SE
final关键字
final:最终的,可以修饰类,变量,方法
特点:
1.final修饰的类不能被继承
2.final修饰的方法不能被子类重写
3.final修饰的变量是常量
注意:
1.静态方法只能访问静态成员,如果要访问非静态成员,需要创建对象
2.非静态方法可以访问任意成员
Static关键字
static可以修饰成员变量也可以修饰成员方法,被static修饰的成员变量和成员方法是类的成员
特点:
1.静态成员可以被本类的所有对象共享
2.静态成员随着类的加载而加载,只加载一次
3.静态成员可以直接被类名调用
注意:
1.静态方法只能访问静态成员,如果要访问非静态成员,需要创建对象
2.非静态方法可以访问任意成员
public class StaticDemo {public static void main(String[] args) {Student s1=new Student();s1.name="张三";Student s2=new Student();s2.show();//我是张三,我来自nullSystem.out.println("----------------");Student.name="李四";s2.show();//我是李四,我来自nullSystem.out.println("----------------");}
}
public class Student {static String name;String school;public void show(){System.out.println("我是"+name+",我来自"+school);}public void method1(){System.out.println(name);System.out.println(school);method2();method3();}public void method2(){}public static void method3(){}public static void method4(){Student s1=new Student();s1.method1();System.out.println(s1.name);System.out.println(s1.school);}
}
集合
List:有序,可重复,有索引
Set:无序,不重复,无索引
1.Collection接口方法
import java.util.*;
class CollectionMain {public static void main(String[] args) {Collection coll = new ArrayList();//清空coll.clear();coll.add(10);coll.add(20);coll.add(30);coll.add(20);// 删除指定元素coll.remove(20);//判断元素是否包含boolean b = coll.contains(10);//true//判断集合是否为空boolean b1 = coll.isEmpty();//false//判断集合的大小int size = coll.size();//3System.out.println(coll);}
}
2.迭代器
import java.util.*;
class CollectionTraversal {public static void main(String[] args) {Collection coll = new ArrayList();coll.add(10);coll.add(20);coll.add(30);coll.add(20);//1.迭代器遍历集合Iterator iterator = coll.iterator();//hasNext()判断目前位置是否有元素while (iterator.hasNext()){//next()返回当前元素并将指针移动到下一个位置Object next = iterator.next();System.out.println(next);}//2.增强for循环遍历集合for(Object a:coll){System.out.println(a);}//3.lambda表达式遍历集合coll.forEach(a -> System.out.println(a));}
}
3.List集合特有方法
import java.util.ArrayList;
import java.util.List;//List集合方法
public class ListFn {public static void main(String[] args) {List<String> list = new ArrayList();//添加元素list.add("a");list.add("b");list.add("c");list.add("d");//在指定位置添加元素list.add(2,"e");System.out.println(list);//获取元素System.out.println(list.get(0));//获取元素的索引System.out.println(list.indexOf("b"));//获取最后一个元素的索引System.out.println(list.lastIndexOf("b"));//判断元素是否存在System.out.println(list.contains("a"));//判断集合是否为空System.out.println(list.isEmpty());//获取集合的大小System.out.println(list.size());//删除元素list.remove("a");list.remove(0);System.out.println(list);//修改元素list.set(0,"f");System.out.println(list);}
}
4.ArrayList
底层原理:
1.新创建的集合,底层为长度为0的数组
2.添加第一个元素时,底层创建一个新的长度为10的数组
3.存满时,扩容1.5倍
4.一次添加多个数据,1.5倍放不下,则新创建的长度以实际为准
5.LinkedList
底层是双链表,查询快,增删慢
6.Set集合
HashSet:无序,不重复,无索引
LinkedHashSet:有序,不重复,无索引
TreeSet:可排序,不重复,无索引
7.HashSet
jdk8以前:数组+链表
1.创建一个默认长度16,默认加载因子0.75的数组
2.计算出应存入的位置
3.判断该位置是否为null,如果是null直接存入
4.如果不是null,调用equals比较属性值
5.一样:不存 不一样:存入,形成链表
jdk8以后:数组+链表+红黑树(链表长度超过8,数组长度大于64)
如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
如果已经重写hashCode方法,不同对象属性相同,计算出的哈希值相同
8.LinkedHashSet
有序、不重复、无索引
原理:底层数据结构是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。
9.TreeSet
s1可排序、不重复、无索引,集合底层是基于红黑树的数据结构实现排序,其增删改查性能都较好
public class TreeSetTest {public static void main(String[] args) {TreeSet<Integer> treeSet = new TreeSet<>();treeSet.add(5);treeSet.add(10);treeSet.add(12);treeSet.add(1);treeSet.add(7);System.out.println(treeSet);//[1, 5, 7, 10, 12]}
}
TreeSet比较规则
import java.util.TreeSet;
public class TreeSetTest {public static void main(String[] args) {//1.javabean类实现Comparable接口指定比较规则(自然排序)默认//2.创建TreeSet对象的时候,传递比较器Comparator指定规则TreeSet<Student> treeSet = new TreeSet<>((o1, o2) -> o1.getAge() - o2.getAge());treeSet.add(new Student("张三",18));treeSet.add(new Student("李四",19));treeSet.add(new Student("王五",17));treeSet.forEach(System.out::println);}
}
10.Map
11.HashMap
源码:
先算出存储元素的地址值
如果地址值不一样,直接根据hash值当下标存储到表中
如果地址值一样,根据hash值当下标存储,
如果当前位置为空,直接存储
如果当前位置有数据,调用equals比较内容是否相同
如果内容相同,不存
如果内容不相同,在同一位置形成链表,存储如下
12.LinkedHashMap
有序,不重复,无索引
13.TreeMap
可排序,不重复,无索引
14.Collections集合工具类
public class TreeSetTest {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();//Collections.addAll()方法可以将数组中的元素添加到集合中Collections.addAll(list,"f","b","c","d");System.out.println(list);//Collections.shuffle()方法可以随机打乱集合中的元素Collections.shuffle(list);System.out.println(list);//Collections.sort()方法可以对集合中的元素进行排序Collections.sort(list);System.out.println(list);//Collections.max()方法可以获取集合中的最大值String max = Collections.max(list);System.out.println(max);}
}
异常
Error:系统级别异常(不用管),例如内存溢出
Exception:
RuntimeException:编译阶段不会出现提示,例如数组越界
运行时异常:编译就会报错
抛出异常
throws:写在方法定义处,表示声明一个异常,告诉调用者使用本方法可能有哪些异常
throw:写在方法里,将异常抛给调用者
自定义异常
目的:让报错信息更见名知意
1.定义异常类
2.写继承关系
3.空参构造
4.带参构造
public class NameException extends RuntimeException {public NameException( ) {}public NameException(String message) {super(message);}
}
多线程
并发:同一时刻,多个指令在单个cpu交替执行
并行:同一时刻,多个指令在多个cpu同时执行
实现多线程方式
1.继承Thread类
public class MyThread extends Thread{@Overridepublic void run() {for(int i=0;i<100;i++){System.out.println(getName() +"123");}}
}
public static void main(String[] args) {MyThread T1 = new MyThread();T1.setName("t1");MyThread T2 = new MyThread();T2.setName("t2");T1.start();T2.start();}
2.实现Runnable
public class MyThread implements Runnable{@Overridepublic void run() {for(int i=0;i<100;i++){//getName是Thread的方法,实现Runnable的话不可用Thread thread = Thread.currentThread();//获取当前线程String name = thread.getName();System.out.println(name+"123");}}
}
public static void main(String[] args) {//创建多线程要执行的任务MyThread T = new MyThread();//创建线程对象Thread thread1 = new Thread(T);Thread thread2 = new Thread(T);thread2.setName("T1");thread1.setName("T2");thread1.start();thread2.start();}
3.多线程
特点:可以获得多线程的返回结果
1.创建类实现Callable接口
2.重写call方法(表示多线程的返回值)
3.创建任务对象
4.创建FutureTask的对象(管理多线程的运行结果)
5.创建THread的对象,并启动
public class MyThread implements Callable<Integer> {@Overridepublic Integer call() {return 100;}
}
public static void main(String[] args) throws Exception {//创建多线程要执行的任务MyThread T = new MyThread();//创建FutureTask对象FutureTask<Integer> task = new FutureTask<>(T);//创建线程对象Thread T1 =new Thread(task);//启动线程T1.start();//获取结果Integer integer = task.get();System.out.println(integer);}
多线程中的常见成员方法
1.获取线程名
getName()
public class MyThread extends Thread {@Overridepublic void run() {System.out.println(getName());}
}
2.设置线程名
setName()
public static void main(String[] args) throws Exception {MyThread myThread = new MyThread();myThread.setName("T1");myThread.start();}
3.获取当前线程对象
Thread.currentThread
public static void main(String[] args) throws Exception {Thread thread = Thread.currentThread();thread.setName("AA");System.out.println(thread.getName());}
4.线程休眠
Thread.sleep(1000)
5.设置线程优先级
getPriority,setPriority
public static void main(String[] args) throws Exception {MyThread myThread = new MyThread();MyThread myThread1 = new MyThread();//获取当前线程优先级 int priority = myThread.getPriority();//设置优先级myThread.setPriority(10);myThread1.setPriority(1);myThread1.start();myThread.start();}
6.守护线程
setDaemon
设置某个线程为守护线程后,若其他线程执行完成,守护线程会陆续结束
public static void main(String[] args) throws Exception {MyThread T1 = new MyThread();MyThread T2 = new MyThread();//设置T2为守护线程T2.setDaemon(true);T1.start();T2.start();}
7.礼让线程
public class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName()+i);//出让cpu礼让权Thread.yield();}}
}
8.插队线程
join()
public static void main(String[] args) throws Exception {MyThread T1 = new MyThread();T1.setName("线程一");T1.start();//表示把T1线程插入到当前线程之前//先执行完T1,在执行Main,不会交替T1.join();for (int i = 0; i < 100; i++) {System.out.println("Main");}}
线程的生命周期
同步代码块
synchronized
public class MyThread extends Thread {static Object o = new Object();@Overridepublic void run() {synchronized (o){System.out.println();}}
}
Lock锁
可以手动获得锁和手动释放锁
new 锁
static Lock lock=new ReentrantLock();
获得锁
lock.lock();
释放锁
lock.unlock();
线程池
无限线程池
public static void main(String[] args) throws Exception {//1.创建线程池对象ExecutorService pool1 = Executors.newCachedThreadPool();//无上限线程池//2.创建任务对象MyThread myThread = new MyThread();//3.提交任务pool1.submit(myThread);//4销毁线程池pool1.shutdown();}
有限线程池
//1.创建有三个线程的线程池对象ExecutorService pool1 = Executors.newFixedThreadPool(3);
自定义线程池
public static void main(String[] args) throws Exception {
// ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor();
// 参数一:核心线程数
// 参数二:最大线程数
// 参数三:空闲线程的最大存活时间
// 参数四:时间单位
// 参数五:任务队列
// 参数六:创建线程工厂
// 参数七:任务的拒绝策略ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, //核心线程数6, //最大线程数60, //空闲线程的最大存活时间TimeUnit.SECONDS, //时间单位new ArrayBlockingQueue<>(3), //任务队列Executors.defaultThreadFactory(), //创建线程工厂new ThreadPoolExecutor.AbortPolicy() //任务的拒绝策略);}
类型转换
字符串--->基本类型
基本类型=基本类型的包装类.parseInt(字符串);
例如
int num1 = Integer.parseInt("123");long num2 = Long.parseLong("123456");double num3 = Double.parseDouble("3.14");boolean flag = Boolean.parseBoolean("true");
字符串/基本类型--->包装类
包装类=包装类.valueOf()
Integer i = Integer.valueOf("456");Long l = Long.valueOf(789L);Double d = Double.valueOf("9.8");Boolean b = Boolean.valueOf(false);
泛型&可变参数
泛型类
//自定义泛型类
public class MyList<E> {
Object[] obj=new Object[10];
int size;
public boolean add(E e){
obj[size]=e;
size++;
return true;
}
public E get(int index){
return (E)obj[index];
}
}
泛型方法
import java.util.ArrayList;
//泛型方法
public class fangxingFn {public static <E> void addAll(ArrayList<E> list,E e1,E e2){list.add(e1);list.add(e2);}
}
可变参数
public class Test {public static int add(int ...a){//可变参数底层是一个数组int len=a.length;int sum=0;for (int i = 0; i < len; i++) {sum+=a[i];}return sum;}
}
Java IO流
存储和读取数据
按流向分为输出流和输入流、
按操作文件类型分为字节流(所有文件)和字符流(文本文件)
字节流
字节输出流
步骤:
1.创建字节输出流对象
OutputStream os = new FileOutputStream("E:\\apps\\1.txt");
2.写出数据
os.write(99);
3.释放资源
os.close();
细节
1.创建字节输出流的对象
1.参数是字符串或者File对象都可以
2.如果文件不存在会自动创建,但要保证父级路径存在
3.如果文件已经存在,会清空文件
2.write的参数是整数,写到文件中的是ASCII的字符
3.使用完流后要释放资源
FileOutputStream写数据的3种方法
void contextLoads() throws Exception {OutputStream os = new FileOutputStream("E:\\apps\\1.txt");//一次写一个os.write(99);// 'c'//写一个字节数组byte[] bytes={97,98,99,100,101};os.write(bytes);//写一个字节数组的一部分os.write(bytes,0,2);os.close();}
换行和续写
换行
@Testvoid contextLoads() throws Exception {OutputStream os = new FileOutputStream("E:\\apps\\1.txt");//写一个字节数组byte[] bytes = "abcdef".getBytes();os.write(bytes);//写一个换行符// '\r\n'os.write("\r\n".getBytes());byte[] bytes2 = "ghijkl".getBytes();os.write(bytes2);os.close();}
续写
new FileOutputStream()的第二个参数,默认是false,表示关闭续写,改为true,表示创建对象时不会清空文件。
@Testvoid contextLoads() throws Exception {OutputStream os = new FileOutputStream("E:\\apps\\1.txt",true);//写一个字节数组byte[] bytes = "abcdef".getBytes();os.write(bytes);os.close();}
字节输入流
步骤:
1.创建字节输入流对象
InputStream is = new FileInputStream("E:\\apps\\1.txt");
2.读数据
一次是读一个数据
int read = is.read();
3.释放资源
is.close();
细节
1.创建字节输入流的对象
1.如果文件不存在会报错
2.读数据
1.read 一次读一个字节,读出来的是数据在ASCII上对应的数字
2.读到文件末尾,read返回-1
3.使用完流后要释放资源
FileInputStream一次读多个字节
public int read(byte[] buffer)
字符流
字符流=字节流+字符集
输入流:一次读一个字节,遇到汉字,一次读多个
输出流:把数据按指定方式编码,变成字节再写到文件中
字符输出流
read():
GBK一次读两个字节,UTF-8一次读三字节,读到后返回二进制转为十进制后的值
读多个数据
传入字节数组改为传入字符数组
void contextLoads() throws Exception {FileReader fr=new FileReader("E:\\apps\\1.txt");//读多个数据fr.read(new char[2]);}
字符输入流
字节缓冲流
创建字节缓冲流
void contextLoads() throws Exception {
//普通流FileInputStream fr=new FileInputStream("E:\\apps\\1.txt");
//缓冲流BufferedInputStream bufferedInputStream = new BufferedInputStream(fr);
//普通流FileOutputStream fileOutputStream = new FileOutputStream("E:\\apps\\1.txt");
//缓冲流BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);}
字节缓冲流原理
字符缓冲流
创建字符缓冲流
转化流
转化流是字符流和字节流之间的桥梁
序列化流
把java对象写到本地文件
1.要写入的对象实现Serializable接口
void contextLoads() throws Exception {Student student = new Student("张三", 18);ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\apps\\1.txt"));objectOutputStream.writeObject(student);objectOutputStream.close();}
反序列流
@Testvoid contextLoads() throws Exception {ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\apps\\1.txt"));Student student = (Student) objectInputStream.readObject();System.out.println(student);}
Java 反射
什么是反射?
反射允许对成员变量,成员方法和构造方法的信息编程访问。
获取class对象的三种方法
Class Clazz1 = Class.forName("com.example.demo.Student");Class Clazz2 = Student.class;Class Clazz3 = new Student().getClass();
反射获取构造方法
Constructor constructor1 = Clazz1.getDeclaredConstructor(): 获取单个构造方法(无参)
Constructor constructor1 = Clazz1.getDeclaredConstructor(String.slass): 获取单个构造方法(只有一个参数,且是String类型)
Constructor constructor1 = Clazz1.getDeclaredConstructor(int.class): 获取单个构造方法(只有一个参数,且是int类型)
获得构造方法的权限修饰符
Constructor constructor1 = Clazz1.getDeclaredConstructor();int modifiers = constructor1.getModifiers();
获得构造方法的参数
Class Clazz1 = Class.forName("com.example.demo.Student");Constructor constructor1 = Clazz1.getDeclaredConstructor(String.class);Parameter[] parameters = constructor1.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter);}
通过反射获得的构造函数获取对象
使用构造函数对象的newInstance方法
Class Clazz1 = Class.forName("com.example.demo.Student");Constructor constructor1 = Clazz1.getDeclaredConstructor(String.class);Student o = (Student) constructor1.newInstance("张三");System.out.println(o);
暴力反射
如果构造方法是私有的,Declared仅仅能让看到这个构造方法,但还是用不了,要使用的话,要对构造方法对象使用setAccessible(true);暂时取消这个限制,叫做暴力反射。
Class Clazz1 = Class.forName("com.example.demo.Student");Constructor constructor1 = Clazz1.getDeclaredConstructor(String.class,int.class);constructor1.setAccessible(true);Student o = (Student) constructor1.newInstance("张三",20);System.out.println(o);
反射获取成员变量
通过变量名获取成员变量
public static void main(String[] args) throws Exception {Class Clazz1 = Class.forName("com.example.demo.Student");Field field = Clazz1.getField("name");System.out.println(field);}
获取成员变量的名字
public static void main(String[] args) throws Exception {Class Clazz1 = Class.forName("com.example.demo.Student");Field field = Clazz1.getField("name");String name = field.getName();System.out.println(name);}
获取对象记录的值
public static void main(String[] args) throws Exception {Class Clazz1 = Class.forName("com.example.demo.Student");Field field = Clazz1.getField("name");//获取成员变量记录的值Student student = new Student("张三", 20);field.get(student);}
修改成员变量记录的值
public static void main(String[] args) throws Exception {Class Clazz1 = Class.forName("com.example.demo.Student");Field field = Clazz1.getField("name");//修改成员变量记录的值Student student = new Student("张三", 20);field.set(student,"李四");System.out.println(student);}
反射获取成员方法
获取指定的单个方法
因为方法重载的可能,所以不仅要指定方法名,还要指定方法的参数类型
public static void main(String[] args) throws Exception {Class Clazz1 = Class.forName("com.example.demo.Student");Method method = Clazz1.getMethod("sleep", String.class);System.out.println(method);}
获取方法的形参
public static void main(String[] args) throws Exception {Class Clazz1 = Class.forName("com.example.demo.Student");Method method = Clazz1.getMethod("sleep", String.class);//获取方法的形参Parameter[] parameters = method.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter);}}
方法运行
public String to(String name){System.out.println(name);return "返回值";}
使用方法.invoke(对象,参数)调用方法
public static void main(String[] args) throws Exception {Class Clazz1 = Class.forName("com.example.demo.Student");Method method = Clazz1.getMethod("to", String.class);Student student = new Student();String re = (String) method.invoke(student, "订单");System.out.println(re);}
Java 注解
注解让其他程序根据注解信息来决定如何执行该程序
声明使用注解
声明注解
public @interface t {String aaa();int bbb();
}
使用
@t(aaa="ttt",bbb = 1)
public class Student {@t(aaa="qqq",bbb=2)public void test(){}
}
如果只有一个value属性可以简写为
public @interface t {String value();
}
@t("ttt")
public class Student {
}
元注解
修饰注解的注解
//声明注解的保留周期
@Retention(RetentionPolicy.RUNTIME)
//注明注解可以用在哪些地方
@Target(ElementType.ANNOTATION_TYPE)
public @interface zj {
}
注解的解析
要解析谁上面的注解,就应该先拿到谁
比如要解析类上的注解,就要先获得类的Class对象
要解析方法的注解,就要先获得方法的Method对象
@zj(value = "装载机",aaa = 99,bbb = {"这种","那种"})
public class Student {@zj(value = "悟空",aaa = 77,bbb = {"这边","那边"})public void test(){}
}
public class DemoApplication {public static void main(String[] args) throws Exception {//1.获得class对象Class aClass = Student.class;//2.解析//判断类上是否包含某个注解if(aClass.isAnnotationPresent(zj.class)){//获得注解zj declaredAnnotation = (zj) aClass.getDeclaredAnnotation(zj.class);//获得注解的值String value = declaredAnnotation.value();double aaa = declaredAnnotation.aaa();String[] bbb = declaredAnnotation.bbb();System.out.println(value);System.out.println(aaa);System.out.println(Arrays.toString(bbb));}}
}
Stream流
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamTest {public static void main(String[] args) {//1.单列集合获取StreamList<Integer> list = new ArrayList<>();Collections.addAll(list,1,2,3,4,5,1);list.stream().forEach(item-> System.out.println(item));//2.双列集合获取StreamMap<String, Integer> map = new HashMap<>();map.put("aaa",111);map.put("bbb",222);map.put("ccc",333);map.put("ddd",444);map.put("eee",555);//获取键的流map.keySet().stream().forEach(item-> System.out.println(item));//以键值对形式放入流map.entrySet().stream().forEach(item-> System.out.println(item));//3.数组获取Streamint[] arr1 = {1,2,3,4,5};Arrays.stream(arr1).forEach(item-> System.out.println(item));System.out.println("------------------------");//filter 过滤list.stream().filter(item->item>3).forEach(item-> System.out.println(item));System.out.println("------------------------");//limit list.stream().limit(3)表示查找前三个list.stream().limit(3).forEach(item-> System.out.println(item));System.out.println("------------------------");//skip list.stream().skip(3)表示跳过前三个list.stream().skip(3).forEach(item-> System.out.println(item));System.out.println("------------------------");//distinct 去重list.stream().distinct().forEach(item-> System.out.println(item));System.out.println("------------------------");//concat 合并流Stream.concat(list.stream(),list.stream()).forEach(item-> System.out.println(item));System.out.println("------------------------");//map 操作流中的每个元素list.stream().map(item->item*2).forEach(item-> System.out.println(item));System.out.println("------------------------");//Stream的终结方法//1.count 统计System.out.println(list.stream().count());//2.collect 收集Set<Integer> list2 = list.stream().collect(Collectors.toSet());System.out.println(list2);}
}