static、final、abstract、transient关键字
static关键字
- static修饰的变量和方法不依赖于类的具体实例,所有类实例共享 同一个static的变量与方法
- static方法不能调用非静态的成员变量。但是非静态方法可以调用静态变量
final关键字
指“最终的”,可以修饰类、方法、变量
- final修饰的类不能被继承
- final修饰的方法不能被子类重写
- final修饰的变量被赋值之后不能再修改
abstract关键字
抽象的,可以修饰类、方法
- 抽象类:该类不能被实例化,往往是被子类继承,有构造器,便于子类实例化。
- 子类继承抽象类,必须实现抽象类中所有的抽象方法才能被实例化。如果没有实现所有的抽象方法,那么该子类也还是一个抽象类,需要用abstract修饰
- 抽象方法:只有声明,没有方法体
- 有抽象方法的类一定是抽象类,抽象类不一定有抽象方法
abstract不能用来修饰属性、构造器、静态方法、final方法、私有方法。
抽象类跟普通类差不多,抽象类多定义了抽象方法。除了不能被实例化之外,并没有任何不同
transient关键字
transient是短暂、瞬变的意思。如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说,用transient关键字标记的成员变量不参与序列化过程。
-
序列化
将对象转换成以字节序列的形式来表示,包含了对象的数据和信息,序列化后可以存在数据库或文件中,也可用于网络传输。序列化之后保存在数据库或文件中,然后反序列化,就会恢复成原来的 Java 对象。
-
transient
关键字的作用在某些情况我们不希望对象被序列化(比如用户的密码、银行卡号),那么可以使用关键字
transient
关掉对象的序列化,被transient
修饰的对象不会被序列化。 注意:static修饰的静态变量本身就是不可被序列化的。 -
transient
只能修饰变量,不能修饰方法和类
对象被transient
修饰,进行序列化保存在数据库或文件后,再被反序列化时,取到的是 null
。
重写、重载
重写:主要是指父类与子类之间,子类重写父类的方法,该方法名相同,参数也相同。final修饰的方法不能被子类重写
重载:可以发生在同一个类中、或子类中,方法名相同,参数个数或类型不同,可以造成重载
抽象类
抽象类不能创建类的实例对象,往往用abstract
修饰。抽象类里面可以包含抽象方法和非抽象方法。抽象方法只是一个声明,没有具体的函数。
// 抽象类
public abstract class Animal {
public void jump(){
System.out.println("我喜欢跳");
}
public abstract void eat();
}
// 子类是具体类
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗狗爱吃肉");
}
}
// 在主函数中
public static void main(String[] args) {
// 多态
Animal a = new Dog();
a.jump();
a.eat();
}
抽象的小问题
A:抽象类有构造方法,不能实例化,那么构造方法有什么用?
用于子类访问父类数据的初始化
B:一个类如果没有抽象方法,却定义为了抽象类,有什么用?
为了不让创建对象
C:abstract不能和哪些关键字共存
a:final 冲突
b:private 冲突
c:static 无意义
抽象类与接口
- 抽象类是对一类具有共性的东西的抽象,接口主要是对动作、操作的描述
- 只能单继承,所以抽象类更复杂,需要设计、考虑其子类可能的所有共性;可以实现多个接口,所以更灵活,局限性相对小
- 接口实际上是抽象类的变种,接口中的所有方法都是抽象的方法
- 接口不允许有方法体,但是抽象类中的方法可以有方法体
- 抽象类、接口都不能被实例化,只能被继承使用
注解的种类
内置注解、自定义注解、元注解
常用内置注解:
@Override
修饰方法,覆盖了父方法@Deprecated
该方法、类、变量等不推荐使用,会有一个删除线@SuppressWarnings
关闭不当的编译器警告信息
元注解,描述其他注解类型
自定义注解:
@interface
//自定义的注解
public @interface MyAnnotation {
String value() default "hello";
}
equals
equals与==的区别
- 对于基本类型只能用==,比较值是否相等
- String一般使用equals比较值是否相等,==比较内存地址是否相等
- 有些不能使用equals比较是否相等,比如StringBuffer。如果想要实现功能需要重写equals方法
String重写的equals方法:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
重写equals的要点、equals方法的性质
- 自反性:如果x不空,则
x.equals(x)
为true - 对称性:x,y都不空,则
x.equals(y)
为true时,y.eqauls(x)
也为true - 传递性:
x.equals(y)
,y.equals(z)
都为true时,z.equals(x)
也为true - 一致性:若x,y引用对象没有发生改变,则反复调用
x.equals(y)
都为相同的结果
String类
String类为什么不可以改变?
private final char value[];
String底层实际上是final的char[]字符数组,数组长度一旦给定就不能改变,所以String不能改变。以下的改变,是指改变了引用内存的指向。sa指向新的内存区域了。
String sa = "abc";
sa += "d";
System.out.println(sa); // abcd
String所谓的不能改变是指,不能在原有的String上做改变,它是new一个新的数组,再复制上去。而StringBuffer是在原有基础上进行修改。
如果想要改变String类,可以用什么方法?
反射。但尽量不要这样使用,会破坏String的不可变性的
String sa = "Hello World";
// 获取value变量
Field valueField = String.class.getDeclaredField("value");
// 因为value是private,需要设置value为可以更改的
valueField.setAccessible(true);
// 获取sa这个对象,转换为char[]类型
char[] valueChar = (char[]) valueField.get(sa);
// 修改值
valueChar[5] = '_';
// 输出 Hello_World
System.out.println(sa);
堆和栈
栈:是内存区域,存储局部变量。凡是定义在方法中的都是局部变量,方法先进栈,变量再进栈。变量用完就会被释放,栈内存更新速度很快,所以局部变量生命周期很短。
堆:存储数组和对象,存储的都是实体。如果数据消失,不代表实体也会消失,所以堆是不会随时释放的。
多态
1. 普通类多态
描述一个事务的多种形态,必须要有父、子类。多态中,父类引用变量调用方法时,会调用子类重写后的方法(向上转型)。如果要使用子类中特有的方法,需要将引用转化为子类类型。
public class Test {
public static void main(String[] args) {
A a = new B();
// 父类型对象调用jump方法为子类重写的方法
a.jump();
// 调用子类的特有方法,需要强制转换
B b = (B) a;
b.run();
}
}
class A {
public void jump() {
System.out.println("class A jump");
}
}
class B extends A {
public void jump() {
System.out.println("class B jump");
}
public void run() {
System.out.println("class B run");
}
}
2. 抽象类多态
abstract class A {...}
class B extends A {...}
A a = new B();
3. 接口多态
需要明确一点,Java中有单继承的局限,但是可以实现多个接口,可以使用多个相关或者不相关的接口对功能进行扩充,因此,接口更加灵活。接口的实现也具有多态性(子类可以重写接口中的方法;多个子类中同名方法包含的功能不一样)。
interface A {...}
class B implements A {...}
A a = new B();
4. 构造器多态
子类继承父类会重写或重载父类的构造器,此时也会形成多态。要注意初始化顺序与销毁清理的顺序。
4.1. 初始化顺序
子类加载必须先加载父类的构造器,因此初始化顺序为:基类先构造加载,然后再按照继承顺序逐步向下初始化。
4.2. 销毁清理顺序
清理顺序与初始化顺序相反。由于子类的销毁方法中可能会调用父类中的方法,因此销毁要从子类开始。所以销毁顺序为:子类先进行清理,然后按照继承顺序向上调用销毁方法,最后调用基类的方法。
注意:static静态方法、final方法(private是final方法)不具有多态性
正则表达式
1. 字符匹配
-
匹配单个任意字符
.
。比如:可以匹配bed
,b^d
,b9d
, 但是不能匹配beed
. -
[]
匹配中括号
中的单个字符。m[abcd]q
可以匹配maq
,mdq
,但是不能mabq
,mhq
. -
|
,相当于或
,匹配指定的单个字符。m(a|b|d|wx)q
可以匹配mwxq
,mbq
, 但不能匹配madq
. -
[^]
表示否定
,[^x]
表示不能是x字符 -
^
匹配字符串开始的位置
2. 次数匹配
- 表示次数:
符号 | 含义 |
---|---|
* | 0次或多次 |
+ | 1次或多次 |
? | 0次或1次 |
{n} | 刚好n次 |
{n,m} | n到m次 |
-
\S
非空字符 -
\s
空字符,表示[\t\n\r\f]
可以匹配一个空格、制表符、回车符、换页符。不能匹配自己输入的多个空格. -
\r
空格符
3. 数字匹配
\d
表示[0-9]
\w
表示[0-9A-Za-z]