java 基础2
---------------------------------------------- 1-1
计算机存储设备的最小信息单元是位(bit), 计算机最小的存储单元是字节(byte,1byte=8bit, 1kb=1024byte)
定义long类型数值后面加L,定义float类型数值后面加F,自动类型转换(低字节赋值给高字节)或强制类型转换(高字节赋值给低字节)不用管这些。
使用+运算符时会自动类型转换,要用高字节类型来接,如:float f = 10 + 2.5F; 但+=可以不用高类型来接如:short s = 10; s += 2 (注意这个2是默认int); 或 s = (short)(s+2)
int i = 10; int j = i++; 此时j等于10,如果是++i那么j就等于11;
数组自动初始化: int[] arr = new int[5]; 数组手动初始化: int[] arr = {0};
--------------------------------------------- 1-13
权限修饰:
private:只能本类使用
默认:只能本包使用
protected: 只能本包和其它包里的子类使用
public:本模块下都可以用
状态修饰:
final: 最终不可变,类不能继承,成员函数不能重写,成员变量不能改变
static: 成员变量被类的所有实例化对象共享,可以通过类名调用,静态方法只能访问静态方法,静态方法只能访问静态变量或常量,普通方法可以访问静态方法也可以访问静态变量或常量,main函数必须是静态的不然运行不了,静态函数里(如main)可以new 其它的类(类没有状态修饰符之说,只有权限修饰),在其它的类里可以各种使用非静态的方法了。总结就是静态修饰的只能访问静态修饰的,非静态修饰的随意
---------------------------------------------------- 1-14
接口默认就是抽象的,接口里的方法默认都是抽象( pubilc abstract )的,接口里的常量默认都是 public static final,接口没有构造函数其实现类构造函数走object()这个无参构造函数
只要一个东西是抽象的(类、接口), 那么继承或实现它的类要实现里面所有的抽象方法,或者本身也是抽象的
内部类(类里一级类):如果是pubilc的可以用 new a().new aa()访问,但一般都是private的要用一个成员函数,成员函数里new它,使用它
局部内部类(成员函数里有个类):在该成员函数里直接new这个类并调用里面的成员函数
匿名函数:new a(){}.show() 实现或重写a里的函数并使用; 也可以给它赋值 a a1 = new a(){}, a1.show() // 不需要重新 class xx{},如果new接口把里面的方法实现即可
--------------------------------------------------- 1-15
异常体系:
Throwablr | ||||
Error 错误,比如硬件什么的有问题,程序处理不了的 |
Exception 异常,程序可以处理的问题 |
|||
RuntimeException 在编译期不检查,运行出现问题后回来改代码 |
非RuntimeException 编译期就检测,出现问题不能编译 |
---------------------------------------------------- 1-21
泛型类: public calss aa<T>{ private T t; public T getT(){return t} public void setT(T t){this.t = t;} }
泛型方法: public calss aa{ public <T> void show(T t){ System.out.println(t); } }
泛型接口: public class c2 { public static void main(String[] args) { aa<String> aa = new aaa<>(); aa.show("哈哈"); aa<Integer> aa2 = new aaa<>(); aa2.show(20); } } interface aa<T>{ void show(T t);} class aaa<T> implements aa<T>{ @Override public void show(T t) { System.out.println(t); } }
类型通配符: // <?> 是任意类型 ArrayList<?> list1 = new ArrayList<>();
ArrayList<?> list2 = new ArrayList<Number>();
ArrayList<?> list3 = new ArrayList<Integer>(); // <? extends Number> 通配符上限:最高类型是Number。 ?继承Number,所以自然?最高是Number //ArrayList<? extends Number> list4 = new ArrayList<Object>(); ArrayList<? extends Number> list5 = new ArrayList<Number>(); ArrayList<? extends Number> list6 = new ArrayList<Integer>(); // <? super Number> 通配符下限:最低类型是Number。 ?是Number的超级,所以自然?最低是Number ArrayList<? super Number> list7 = new ArrayList<Object>(); ArrayList<? super Number> list8 = new ArrayList<Number>(); //ArrayList<? super Number> list9 = new ArrayList<Integer>();
------------------------------------------------------- 1-24
将字符转换(解析)成二进制数据存到计算机里叫编码,将二进制数据按照某种规则转化(解析)为字符串显示出来叫解码(注:按照A规则编码就得按照A规则解码,否则乱码)。
字符集是系统提前支持的字符的集合(解码显示),也就是要提前支持的某个字符集合解码,为啥能提前支持某个字符的集合解码(显示)因为提前支持了那个字符的集合的编码。比如系统提前支持ASXLL字符的集合(也就字符集),那相对应的也必须支持这个字符集的编码规则(字符编码)
------------------------------------------------------ 2-8
list(普通模式):
ArrayList: 数组结构(查询快,增删慢)
LinkedList: 链表结构(查询慢,增删快,有特有方法(在头或者尾增删数据等))
set(不重复,哈希表结构):
HashSet: 没有顺序
LinkedHashSet: 正常顺序
TreeSet: 重写方法,自定义顺序
map(有键值对):
HashMap: 有键值对
-------------------------------------------------- 2-24
线程:
第一种方法创建线程:一个类继承 Thread 并重写里面的 run 方法,则创建了一个线程(run方法) --> 实例化这个对象并.start(),则开始执行这个线程
在 run 方法里面使用 getName() 是获取这个线程的名字,会有一个默认的比如什么 thread0、thread1什么的,也可以自己设置:实例化这个对象并.setName("团团") 或者在有参构造里 super(name)
ts1.getPriority():返回ts1线程的优先级(默认是5,最小是1,最大是10);ts1.setPriority(6):设置ts1线程的优先级为6。// 优先级越高只是表示有更大的几率抢到cpu的执行权,优先级都一样的话就随机抢
在 run 里 使用 Thread.sleep(1000) 为此线程暂停1000ms
ts1.start() 后,ts1.jion() 表示要等ts1线程执行完, 后面的线程才可以执行
使用 Thread.currentThread() 是获取主线程(正在执行的,比如main(),示例:Thread.currentThread().getName()、Thread.currentThread().setName("团团") ),ts1.setDaemon(true) 表示将ts1线程设置为守护线程,守护主线程,主线程执行完了,守护线程即ts1马上就完了
第二种方法创建线程:一个类实现 Runnable 接口并重写里面的 run 方法,则创建了一个线程(run方法) --> new Thread(类名,"自定义线程名").start(), 则开始执行这个线程 // 这样有个好处实现类还能继承其它的类,这样在run里获取线程名要用 Thread.currentThread().getName。使用Lambda表达式:new Thread( () -> xxx ).start(); 或 Runable r = () -> xxx; new Thread(r).start;
------------------------------------------------- 2-26
关闭端口:
C:\Users\fengxingwang>netstat -ano | findstr 1116 // 查看使用1116端口号的进程
TCP 0.0.0.0:1116 0.0.0.0:0 LISTENING 20512
TCP [::]:1116 [::]:0 LISTENING 20512
C:\Users\fengxingwang>taskkill -PID 20512
错误: 无法终止 PID 为 20512 的进程。
原因: 只能强行终止这个进程(带 /F 选项)。
C:\Users\fengxingwang>taskkill -PID 20512 -F
成功: 已终止 PID 为 20512 的进程。
------------------------------------------------- 2-27
并行运行:
run --> Edit Configurations --> 左边选要并行运行的类,右边点 Modify options 下拉选择框里把 Allow multiple instances(允许多个实例)
接口更新概述:
之前接口的概述(见1-14):常量默认都是 pubilc static final,方法默认都是 public adstract
在以上基础上有做更新:默认方法(Java 8)、静态方法(java9)、私有方法(java9)
默认方法:在接口里加 default void newFunction(){ xxx } 即可,之前的实现类不会报错,实现类也可以使用或重写(重写的时候不要加default)这个newFunction,因为如果一个接口需要新增一个方法,那之前实现它的类都会报错(因为没全部重写),除非你新加一个接口继承老接口然后写新方法(这样之前实现此接口的类就不会报错),但是这样太麻烦,新加一个方法就要新写一个接口继承老接口。
静态方法:在接口里加 static void function(){ xxx } 即可,注意静态方法只能由该接口调用,因为如果一个类同时实现多个接口(接口可以多实现,类只能单继承,多层继承),接口里的静态方法名字一样,如果实现类可以调用的话就不知道该调用哪个接口里的静态方法了。
私有方法:在接口里加 private void function(){ xxx } 即可,因为如果接口里的默认方法或者静态方法有大量重复的代码要怎么提取出来呢,所以可以把重复的代码放到私有方法里,默认方法或者静态方法调用此私有方法就好了,注意:接口的静态方法要使用接口的静态私有方法(private static void function(){ xxx },见1-13)
函数式接口:
有且只有一个抽象方法的接口,只有这样java中的Lambda才能顺利的进行推导,它可以用作方法的形参传递(这样就可以使用Lambda表达式作为实参传递),也可以用作局部变量( 接口名 my = () -> xxxx; ), 也可以作为方法的返回值(这样直接返回一个Lambda表达式也可以),函数式接口有注解 @FunctionalInterface,常用的函数式接口有(一般在java.util.function): Supplier、Consumer、Predicate、Function、Runnable(创建线程)、Comparator(比较器)
接口的调用和实现:
和main同级有个方法。它的形参是一个接口,它里面有形参.接口里的方法,然后传2个具体形参(这里就是调用并初始化(正常传参使用它),参考正常在main里new接口的实现类也是一样,如果有返回值就可以得到结果并使用它)。然后在main里调用这个方法,使用匿名函数重写接口里面的方法的时候形参就不会是具体的形参(这里就是具体的实现,具体的实现形参不会是具体的,参考普通类实现接口也是一样)。如果使用Lambda表达式注意只能用于接口,且此接口只有一个成员方法
Lambda表达式:
Lambda表达式形参的类型不用写,如果只有一个形参小括号可以省略,如果代码块只有一句话大括号和分号可以省略(如果这一句话里有return,return也必须省略),Lambda表达式不会生成class字节码文件,它是动态的,匿名函数其实会生成一个class字节码文件(相对于新建了一个class),Lambda表达式只能用于只有一个抽象方法的接口即函数式接口,它是根据 “可推导就是可省略的原则” ,所以不用指定参数类型,不用重载接口里的方法
方法引用( function是和main同级的方法,形参是接口):
方法引用符: ::
Lambda表达式:function( s -> System.out.println(s));
方法引用:function(System.out::println) // 引用了System.out对象里的println方法,println方法的参数就是s,它是Lambda的孪生兄弟,一般可以用Lambda就可以用方法引用替换
--------------------------------------------- 2-28
Stream流:
体验:list1.stream().filter(s -> s.startsWith("a")).filter(s -> s.length() == 3).forEach(s-> newList.add(s)); 共分为生成流、操作流、结束流
生成流:
操作流 (一般都在Stream接口里面) :
list1.stream().filter(s -> s.startsWith("a")).filter(s -> s.length() == 3).forEach(s-> newList.add(s))
ArrayList<String> list = new ArrayList<>(); list.add("111"); list.add("222"); list.add("333"); list.add("444"); list.add("555"); list.add("666"); // 1 取list前3个数据输出 list.stream().limit(3).forEach(System.out::println); // 2 跳过3个元素,输出剩下的 list.stream().skip(3).forEach(System.out::println); // 3 跳过2个元素,把剩下的前2个输出 list.stream().skip(2).limit(2).forEach(System.out::println);
ArrayList<String> list = new ArrayList<>(); list.add("111"); list.add("222"); list.add("333"); list.add("444"); list.add("555"); list.add("666"); // 1 取前4个数据组成一个Stream流 Stream<String> s1 = list.stream().limit(4); // 2 跳过2个元素组成一个Stream流 Stream<String> s2 = list.stream().skip(2); // 3 合并需求1和2的Stream流组成一个新的Stream流,输出 concat是静态方法 Stream.concat(s1, s2).forEach(System.out::println); // 4 合并需求1和2的Stream流组成一个新的Stream流,去重,输出 Stream.concat(s1, s2).distinct().forEach(System.out::println);
ArrayList<String> list = new ArrayList<>(); list.add("cccc"); list.add("bbbb"); list.add("aaa"); list.add("dddddd"); // 1 按字母顺序排序(自然排序) //list.stream().sorted().forEach(System.out::println); // 2 按长度排序,最长的排前面(a.length() - b.length() 就是最短的在前面) list.stream().sorted((a, b) -> b.length() - a.length()).forEach(System.out::println); // 3 按长度排序,最长的排前面,长度一样就按字母顺序排序(自然排序) list.stream().sorted((a, b) -> { int len = b.length() - a.length(); int num = len == 0 ? a.compareTo(b) : len; return num; }).forEach(System.out::println);
ArrayList<String> list = new ArrayList<>(); list.add("10"); list.add("20"); list.add("30"); // 1 将集合中的字符串转为整数,输出 list.stream().map(s->Integer.parseInt(s)).forEach(System.out::println); // map 可以遍历每个元素然后操作它 list.stream().map(Integer::parseInt).forEach(System.out::println); // mapToInt 也可以遍历每个元素然后操作它并且返回一个IntStream流,IntStream接口里有sum、max、min等方法 list.stream().mapToInt(Integer::parseInt).forEach(System.out::println); // int sum() 返回流中元素的总和 int sum = list.stream().mapToInt(Integer::parseInt).sum(); System.out.println(sum);
终结流:
ArrayList<String> list = new ArrayList<>(); list.add("10"); list.add("20"); list.add("30"); list.add("39"); // 1 输出 list.stream().forEach(System.out::println); // 2 统计几个以3开头的 long count = list.stream().filter(s -> s.startsWith("3")).count(); System.out.println(count);
综合练习:
ArrayList<String> manList = new ArrayList<>(); manList.add("周瑞发"); manList.add("成龙"); manList.add("刘德华"); manList.add("吴京"); manList.add("周星驰"); manList.add("李连杰"); ArrayList<String> womanList = new ArrayList<>(); womanList.add("林心如"); womanList.add("张曼玉"); womanList.add("林青霞"); womanList.add("柳岩"); womanList.add("林志玲"); womanList.add("王祖贤"); // 1 男演员只要名字长度3个字的前3人 Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3); // 2 女演员只要姓林的,并且不要第一个 Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1); // 3 把过滤后的男演员和女演员合在一起 Stream<String> concatStream = Stream.concat(manStream, womanStream); // 4 将合流的成员作为构造函数参数传递 //concatStream.map(s -> new c2(s)).forEach(System.out::println); // 此时s就是一个个实例 //concatStream.map(s -> new c2(s)).forEach(s->{ System.out.println(s.getName());}); concatStream.map(c2::new).forEach(s-> System.out.println(s.getName())); // 一步写完 Stream.concat(manList.stream().filter(s -> s.length() == 3).limit(3), womanList.stream().filter(s -> s.startsWith("林")).skip(1)).map(c2::new).forEach(s-> System.out.println(s.getName()));
Stream流转换为集合(也叫收集):
// --------------------- Stream转为List ArrayList<String> list = new ArrayList<>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("柳岩"); // 1 得到名字为3个字的,再转为ArrayList Stream<String> listStream = list.stream().filter(s -> s.length() == 3); List<String> newList = listStream.collect(Collectors.toList()); for(String i:newList){ //System.out.println(i); } // --------------------- Stream转为Set HashSet<Integer> set = new HashSet<>(); set.add(10); set.add(20); set.add(30); // 1 得到大于10的,再转为HashSet Stream<Integer> setStream = set.stream().filter(s -> s > 10); Set<Integer> newSet = setStream.collect(Collectors.toSet()); for (Integer i:newSet){ //System.out.println(i); } // --------------------- Stream转为Map集合 String[] s1 = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"}; // 得到年龄大于25的,并转到Map集合 Stream<String> stringStream = Stream.of(s1).filter(s -> Integer.parseInt(s.split(",")[1]) > 25); Map<String, String> newMap = stringStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> s.split(",")[1])); Set<String> key = newMap.keySet(); for (String i:key){ String val = newMap.get(i); System.out.println(i + "," + val); }
-------------------------------------- 3-1
反射:
概念:就是在运行时去获取一个类的信息(成员方法、变量等),然后通获取到的信息来创建对象并调用方法。想要用反射去使用一个类,首先要获取那个类的字节码文件对象(类型为class的对象)
// ------------ 第1种方式 Class<Student> c1 = Student.class; Class<Student> c2 = Student.class; System.out.println(c1 == c2); // true 同一个类它的字节码文件都是相等的 // ----------- 第2种方式 Student s = new Student(); Class<? extends Student> c3 = s.getClass(); System.out.println(c1 == c3); // true // ----------- 第3种方式(这种方式最灵泛,可以把需要的字符串形参配置到一个配置文件里面,这样通过修改配置文件的内容加载不同的字节码文件) Class<?> aClass = Class.forName("p11.p2.c"); // p11是包,p2是p11下的包 System.out.println(aClass); // class p11.p2.c
// 获取Class对象(字节码文件) Class<?> c = Class.forName("p1.p2.Student"); // 后面主要使用Class的方法 // 返回所有public的构造方法 Contructor<?> cons = c.getConstructors(); // 返回所有权限的所有构造方法(私有的呀、默认的呀(类的默认的就是什么都不带)) Contructor<?> cons = c.getDeclaredConstructors(); // 拿单个public的无参构造方法,这个操作等同于 Student s = new Student(); Constructor<?> con = c.getConstructor(); // 拿的是无参的所以没有参数 Object obj = con.newInstance() // 拿三个形参的public的构造方法,这个操作等同于 Student s = new Student("林青霞", 30, "刘岩"); Constructor<?> con = c.getConstructor(String.class, int.class, String.class); // 拿三个参数的构造方法,注意这里的形参是class类型,基本数据类型也可以通过.class得到对应的class类型 Object obj = con.newInstance("林青霞", 30, "刘岩"); // 拿单个所有权限的构造方法 Constructor<?> con = getDeclaredConstructor(String.class); con.setAccessible(true); // 值为true,取消访问检查 Object obj = con.newInstance("林青霞"); // 正常说不能通过私有的构造方法来创建对象,但反射可以,需要在上一步取消访问检查
Class<?> c = Claas.forName("p1.p2.Student") // getFields()、getDeclaredFields()、getField(Strinf name)、getDeclaredField(String name),对应public数组、全部权限数组、单个pubilc、单个全部权限 Constructor<?> con = c.getConstructor(); Object obj = con.newInstance() Field addressField = c.getField("address"); addressField.set(obj, "西安“); // obj 可以是new的 // 访问私有的 Field ageField = c.getField("age"); ageField.setAccessible(true); ageField.set(obj,30) // obj 可以是new的
Class<?> c = Claas.forName("p1.p2.Student") // getMethods()、getDeclaredMethods()、getMethod(String name, Class<?>...)、getDeclaredMethod(String name, Class<?>...),对应public数组、全部权限数组、单个pubilc、单个全部权限 Constructor<?> con = c.getConstructor(); Object obj = con.newInstance() Method m = c.getMethod("fun1"); m.invoke(obj); // 访问私有的 Method m2 = c.getDeclaredMethod("fun2", String.class, int.class); m2.setAccessible(true); m2.m.invoke(obj);
ArrayList<Integer> array = new ArrayList<>(); // 此集合需要Integer类型参数, 但我要添加字符串类型,需要用反射,反射可以越过泛型检查 Class<? extends ArrayList> c = array.getClass(); Method m = c.getMethod("add", Object.class); m.invoke(array, "aaa"); m.invoke(array, "bbb"); m.invoke(array, "ccc");
反射和配置文件txt的使用:
------------------------------- 3-2
模块化:
// 在m1模块的src下新建 module-info.java module m1{ exports p1; // 导出被使用的包 } // 在m2模块的src下新建 module-info.java module m2{ requires m1; // 导出m1模块的配置信息文件,如果报错就 alt + enter 选add denendecy on ...... }
module m1{ provids a1(接口名) with c1(实现此接口的类名);// 把接口和实现类都导出去 } module m2{ requires m1; uses a1; // 使用m1里导出的接口 } // 使用m1模块里的a1接口的方法: ServiceLoader<a1> a1s = ServiceLoader.load(a1.class); for(a1 i :a1s){ i.test(); // test()是a1接口的抽象方法,最终会使用provids a1 with c1 里的c1实现类,这个可以改成其它的实现类 }
本文来自博客园,作者:封兴旺,转载请注明原文链接:https://www.cnblogs.com/fxw1/p/15756310.html