javaweb备忘录
javase
static
- 静态方法属于类,所以在静态方法中,无法获取成员变量的值,但是静态方法可以访问到静态变量
- 所有被标记为静态的内容,会在类刚加载的时候就分配,而不是在对象创建的时候分配,所以说静态内容一定会在第一个对象初始化之前完成加载。
package
包类似于C++中的namespace
当前类 | 同一个包下的类 | 不同包下的子类 | 不同包下的类 | |
---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | ❌ |
默认 | ✅ | ✅ | ❌ | ❌ |
private | ✅ | ❌ | ❌ | ❌ |
类的继承
- 标记为
final
的类不允许被继承: - 父类中将属性的访问权限修改为
private
,那么子类将无法访问,但是依然继承了这个属性 - 如果父类存在一个有参构造方法,子类必须在构造方法中调用
- 在使用子类时,可以将其当做父类来使用,也可以使用强制类型转换,将一个被当做父类使用的子类对象,转换回子类
a instanceof b
判断a是否是b的一个子类或者实例- 子类可以定义和父类同名的属性,这时可以使用
super
关键字来表示父类 - 所有类都默认继承自Object类
a.equals(b)
用于比较a,b是否是同一个对象
重写override
- 方法的重载是为某个方法提供更多种类,而方法的重写是覆盖原有的方法实现
- 重写方法要求与父类的定义完全一致
- 静态方法不支持重写,因为它是属于类本身的,但是它可以被继承。
- 我们如果不希望子类重写某个方法,我们可以在方法前添加
final
关键字,如果父类中方法的可见性为private
,那么子类同样无法访问 - 在重写父类方法时,如果希望调用父类原本的方法实现,那么同样可以使用
super
关键字 - 子类在重写父类方法时,不能降低父类方法中的可见性,但是可以在子类中提升权限
抽象类
- 子类,必须要实现抽象类中所有抽象方法,无法直接通过new关键字来直接创建对象
- 抽象方法的访问权限不能为
private
接口
- 接口一般只代表某些功能的抽象,接口包含了一些列方法的定义,类可以实现这个接口,表示类支持接口代表的功能
- 从Java8开始,接口中可以存在方法的默认实现
- 接口中不允许存在成员变量和成员方法,但是可以存在静态变量和静态方法,接口中定义的静态变量只能是public static final
- 接口是可以继承其他接口,相当于是对接口功能的融合
深浅复制
- 虽然Student对象成功拷贝,但是其内层对象并没有进行拷贝,依然只是对象引用的复制,所以Java为我们提供的
clone
方法只会进行浅拷贝 - 枚举类型的本质就是一个普通的类,但是它继承自
Enum
类,我们定义的每一个状态其实就是一个public static final
的Status类型成员变量,可以给枚举类型添加独有的成员方法
包装类
- byte -> Byte
- boolean -> Boolean
- short -> Short
- char -> Character
- int -> Integer
- long -> Long
- float -> Float
- double -> Double
包装类型支持自拆装箱,可以直接将一个对应的基本类型值作为对应包装类型引用变量的值,当然也可以相反
Integer i = 10;
Integer i = 10; int a = i;
通过自动装箱转换的Integer对象,如果值相同,得到的会是同一个对象,这是因为存在IntegerCache,如果在范围内,那么会直接返回已经提前创建好的对象,IntegerCache会默认缓存-128~127之间的所有值,如果超出这个缓存范围的话,就会得到不同的对象了
BigDecimal可以实现小数和极大树的精确计算。
1
2
3int[] array = new int[10];
类型[] 变量名称 = new 类型[]{...}; //静态初始化(直接指定值和大小)
类型[] 变量名称 = {...}; //同上,但是只能在定义时赋值
字符串
Java中没有字符串这种基本类型,因此只能使用类来进行定义,每个用双引号括起来的字符串,都是String类型的一个实例对象
如果是直接使用双引号创建的字符串,如果内容相同,为了优化效率,那么始终都是同一个对象
字符串的内容比较,一定要用equals
字符串和字符数组的转换
char[] chars = str.toCharArray();
String str = new String(chars);
str.matches("[abc]*")
调用正则表达式进行匹配,返回bool值
类
成员内部类中,可以访问到外层的变量
静态内部类就像静态方法和静态变量一样,是属于类的,可以直接创建使用,但无法访问到外部类的非静态内容 不需要依附任何对象,就可以直接创建静态内部类的对象
1
2
3
4
5
6
7public class Test
public static class Inner {
public void test() {
System.out.println("我是静态内部类!");
}
}
}
在new的时候,后面加上花括号,内部可以定义一个匿名类Student student = new Student() {}
此时创建出来的Student对象,就是一个已经实现了抽象方法的对象
Lambda表达式
- 标准格式为:
([参数类型 参数名称,]...) ‐> { 代码语句,包括返回值 }
- 和匿名内部类不同,Lambda仅支持接口,不支持抽象类
- 接口内部必须有且仅有一个抽象方法(可以有多个方法,但是必须保证其他方法有默认实现,必须留一个抽象方法出来)
1 | public interface Study { |
方法引用其实本质上就相当于将其他方法的实现,直接作为接口中抽象方法的实现。任何方法都可以通过方法引用作为实现
成员方法因为需要具体对象使用,所以说只能使用 对象::方法名 的形式
构造方法也可以被引用,使用new表示
所有的运行时异常都继承自RuntimeException
断言表达式需要使用到assert
关键字,如果assert后面的表达式判断结果为false,将抛出AssertionError错误。
泛型
泛型在定义时并不明确是什么类型,而是需要到使用时才会确定对应的泛型类型。
public class Score<T>
类似cpp的模板
因为是具体使用对象时才会明确具体类型,所以静态方法中无法使用
如果要让某个变量支持引用确定了任意类型的泛型,那么可以使用?
通配符
Test<?> test = new Test<Integer>();
泛型只能确定为一个引用类型,基本类型是不支持的(不包括数组,数组本身是引用类型),如果要存放基本数据类型的值,只能使用对应的包装类
当子类实现泛型接口时,我们可以选择在实现类明确泛型类型,或是继续使用此泛型让具体创建的对象来确定类型,继承等同理
在泛型变量的后面添加extends
关键字即可指定上界,使用时,具体类型只能是我们指定的上界类型或是上界类型的子类public class Score<T extends Number>
在进行类型判断时,不允许使用泛型,只能使用原始类型
泛型类不支持创建参数化类型数组(类型擦除导致的,运行时不会检查具体类型是什么)
Test<String> test = new Test<>(); System.out.println(test instanceof Test);
函数式接口
函数式接口就是JDK1.8专门为我们提供好的用于Lambda表达式的接口,这些接口都可以直接使用Lambda表达式
**Supplier供给型函数式接口:这个接口是专门用于供给使用的,其中只有一个get方法用于获取需要的对象
Consumer消费型函数式接口:这个接口专门用于消费某个对象的。
Function函数型函数式接口:这个接口消费一个对象,然后会向外供给一个对象(前两个的融合体)
Predicate断言型函数式接口:接收一个参数,然后进行自定义判断并返回一个boolean结果。
1 | private static void test(String str) |
Optional
String s = Optional.ofNullable(str).get(); //get方法可以获取被包装的对象引用,但是如果为空的话,会抛出异常
String s = Optional.ofNullable(str).orElse("我是为null的情况备选方案");
java的集合类(如果两个对象使用equals
方法相等,那么集合中就是相同的两个对象):
ArrayList
List,有序线性表
LinkedList,双向链表
只要是实现了迭代器接口的类(可以自己实现),都可以使用
foreach
语法:1
2
3
4
5Iterator<String> iterator = list.iterator();
while (iterator.hasNext())
{ //每次循环一定要判断是否还有元素剩余
System.out.println(iterator.next());
}ListIterator是对list类的特化双向迭代器
Queue队列,Deque双向队列,其中deque有正反向的迭代器
descendingIterator
和iterator
PriorityQueue优先级队列,可以自己实现
Comparator
接口Set集合,不允许出现重复元素,不支持随机访问
- HashSet,哈希实现,无法维持插入顺序
- TreeSet,元素插入时排序
Collections是专用于集合操作的工具类,类似Array
Map映射,新插入的相同键会覆盖原来的,在获取一个不存在的映射时,默认会返回null作为结果(可以设置默认值)
- 默认不维护插入顺序,LinkedHashMap实现维护
Stream流水线,有点像numpy的管道
1
2
3
4list = list //链式调用
.stream() //获取流
.filter(e -> !e.equals("B")) //只允许所有不是B的元素通过流水线
.collect(Collectors.toList()); //将流水线中的元素重新收集起来,变回List
I/O操作
FileInputStream inputStream = new FileInputStream("路径");
inputStream.available(); //查看剩余数量
inputStream.read((byte[]) bytes); //一次性读取全部内容(返回值是读取的字节数)
- 输出流使用
write()
类似read - 字符流是以一个具体的字符进行读取,因此它只适合读纯文本的文件,如果是其他类型的文件不适用
FileReader | FileWriter
- 为了避免频繁I/O,可以使用缓冲字节流
BufferedInputStream
缓冲字符流BufferedReader
- 转换流
InputStreamReader和OutputStreamWriter
用于将字符信息转换成字节用于流的输入输出 - 打印流
PrintStream
可以控制打印到的对象(向文件打印则是一个文件输出流对象),默认是控制台,Scanner
默认接受系统输入流,也可以指定输入流 - 数据流
DataInputStream | dataOutputStream
用于写入基本数据类型 - 对象流
ObjectOutputStream
用序列化形式存储对象(也可以让某些属性不序列化),用private static final long serialVersionUID
作为类的标识用于区分版本,并且用于从流式数据还原出对象
java的多线程
- 创建Thread对象来创建一个新的线程,Thread构造方法中需要传入一个Runnable接口的实现(在另一个线程执行的内容逻辑)
- 调用
sleep()
方法来将当前线程进入休眠;interrupt()
方法给指定线程添加一个中断标记以告知线程需要立即停止运行或是进行其他操作,由线程来响应此中断并进行相应的处理 - 优先级
- MIN_PRIORITY 最低优先级
- MAX_PRIORITY 最高优先级
- NOM_PRIORITY 常规优先级
yield()
方法来将当前资源让位给其他同优先级线程;使用join()
方法来实现线程的加入,让一个线程等待加入的线程执行完成后再继续进行- synchronized关键字创造一个线程锁;
jstack
命令来检测死锁; - 对象的
wait()
方法会暂时使得此线程进入等待状态,同时会释放当前代码块持有的锁,这时其他线程可以获取到此对象的锁,当其他线程调用对象的notify()
方法后,会唤醒刚才变成等待状态的线程(这时并没有立即释放锁)。必须是在持有锁的情况下使用 - ThreadLocal类,来创建工作内存中的变量,不同的线程访问到ThreadLocal对象时,都只能获取到当前线程所属的变量
- 可以通过创建一个Timer类来让它进行定时任务调度,并且该类维护
TaskQueue
和TimerThread
循环读取任务,闲则wait
,调用cancel()
方法来关闭工作线程 - 其他所有的非守护线程结束之后,守护线程自动结束,守护线程中产生的新线程也是守护的
t.setDaemon(true)
反射
反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够知道这个类所有的属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。
在Java程序启动时,JVM会将一部分类(class文件)先加载(并不是所有的类都会在一开始加载),通过ClassLoader将类加载,在加载过程中,会将类的信息提取出来(存放在元空间中,JDK1.8之前存放在永久代),同时也会生成一个Class对象存放在内存(堆内存),注意此Class对象只会存在一个,与加载的类唯一对应
反射机制利用这些存放的类信息Class对象,来获取类的信息和操作类。
通过反射可以对类进行精准的判断,精细区分子类,父类
可以通过反射来创造类对象,调用类的方法(本质上还是类的实例进行调用)只是利用反射机制实现了方法的调用,并且这些对类的操作可以无视权限控制,也可以去除final关键字
这样一来,就可以通过编译完的class文件来反向操作其中的类
注解
注解可以被标注在任意地方,与注释不同的是,注解可以通过反射在运行时获取,注解也可以选择是否保留到运行时。
可以在注解中定义一些属性,注解的属性也叫做成员变量,注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型.如String value();
可以使用getAnnotations()
方法来快速获取我们标记的注解。
- @Override - 检查(仅仅是检查,不保留到运行时)该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告(仅仅编译器阶段,不保留到运行时)
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
元注解是作用于注解上的注解,用于我们编写自定义的注解:
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
java新特性:
- 8:只有一个方法要实现的类可以直接传入一个匿名函数,匿名函数的写法也可以简化,比如只有一个参数时省略括号
- 方法引用,包括静态方法,对象的方法,构造函数等
- Optional用于处理空指针异常
- 9:创建一个新的项目,并在
src
目录下,新建module-info.java
文件表示此项目采用模块管理机制,模块内部对能够对库以模块为单位调用 - 如果模块没有明确授权给其他模块使用反射的权限,那么其他模块是不允许使用反射进行修改的,也可以用
open
开放反射 - 模块可以指定对某些接口的依赖
jshell
可以进行交互式编程- 接口可以提供private实现
- 集合类可以用
of
方法快速创建,但创建后无法修改 - 10:
var
自动类型推断,类似c++,只发生在编译期间 - 11:全新的
Http Client API
,支持最新的HTTP2和WebSocket协议 - 12-16:更简洁的switch,有类似python的yield
- 三引号表示复杂字符串,特殊符号不需要转义
- 类似
if(obj instanceof Student student)
的语法可以直接进行安全的类型转化 - Account类可以直接提供一个有name和passwd大部分功能的类
- 17:秘封类可以指定能继承的子类,其他类无法继承
public sealed class A permits B //在class关键字前添加sealed关键字,表示此类为密封类型,permits后面跟上允许继承的类型,多个子类使用逗号隔开
gui组件
awt:
1 | public class better_gui { |
swing:
Swing 是在AWT的基础上构建的一套新的图形界面系统,它提供了AWT 所能够提供的所有功能,并且用纯粹的Java代码对AWT 的功能进行了大幅度的扩充。通常把Swing控件称为轻量级控件
swing不依赖操作系统,可以跨平台实现统一的外观效果
Swing在没有设定布局时,组件的坐标原点并不是窗口的左上角,而是窗口标题栏下方的左上角:
1 | public class swing_gui { |
javaweb
- 使用PreparedStatement防止sql注入
- 数据库的查询结果映射为java类时,为了进行类型转换需要一个无参数构造方法