Java小白开始每日刷题,并记录刷题遇到的一些知识点,大佬们多多包涵,内容可能会比较杂乱,如果不太详细尽情谅解!!!希望对一些人有所帮助!!!
本次整理了与继承、static、IO流、方法的重写与重载、类加载机制、正则表达式相关的一些基础知识点。
上期链接
11. 继承相关
11.1 继承
继承的概念
继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法
继承可以让类与类之间产生关系,子类可以使用父类中的非私有成员
通过extends实现
示例代码
public class Fu {
public void show() {
System.out.println("show方法被调用");
}
}
public class Zi extends Fu {
public void method() {
System.out.println("method方法被调用");
}
}
public class Demo {
public static void main(String[] args) {
//创建对象,调用方法
Fu f = new Fu();
f.show();
Zi z = new Zi();
z.method();
z.show();
}
}
11.2 继承的特点
Java中类只支持单继承,不支持多继承
Java中类支持多层继承
Java中所有的类都直接或者间接继承于Object类
代码演示
public class Granddad {
public void drink() {
System.out.println("爷爷爱喝酒");
}
}
public class Father extends Granddad {
public void smoke() {
System.out.println("爸爸爱抽烟");
}
}
public class Mother {
public void dance() {
System.out.println("妈妈爱跳舞");
}
}
public class Son extends Father {
// 此时,Son类中就同时拥有drink方法以及smoke方法
}
11.3子类到底能继承父类中的哪些内容?
11.3.1 构造方法
子类不能继承父类里的构造方法
11.3.2 成员变量
子类可以继承父类的private变量,但不能直接用
11.3.3 成员方法
子类可以继承非私有的成员方法,不可以继承私有的成员方法
虚方法表:非private、static、final修饰的方法
11.4 继承中的特点
11.4.1 继承中成员变量的访问特点
在子类中访问一个变量,采用的是就近原则:
子类局部范围开始往上找
子类成员范围开始往上找
父类成员范围开始往上找
代码实例:
class Fu {
public void eat(){
System.out.println("吃米饭");
}
public void drink(){
System.out.println("喝水");
}
}
class Zi extends Fu{
@Override
public void eat(){
System.out.println("吃炸鸡");
}
@Override
public void drink(){
System.out.println("喝可乐");
}
public void launch(){
//先在本类中查看eat和drink方法,如果有,就会调用子类的;如果没有,就会调用从父类继承下来的方法
this.eat(); //吃炸鸡
this.drink(); //喝可乐
super.eat(); //吃米饭
super.drink(); //喝水
}
}
11.4.2 继承中构造方法的访问特点
父类中的构造方法不会被子类继承
注意:子类中所有的构造方法默认都会访问父类的无参构造方法,隐式语句 super(),再执行自己
子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()
问题:如果父类中没有无参构造方法,只有带参构造方法呢?
通过使用super关键字去显示的调用父类的带参构造方法
子类通过this关键字去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参构造方法
注意:this(...) super(...)必须放在构造方法的第一行有效语句,并且二者不能共存
代码示例:
public class Fu {
String name;
public Fu() {
System.out.println("父类的无参构造");
}
public Fu(String name) {
this.name = name;
}
}
public class Zi extends Fu {
public Zi() {
//子类构造方法中隐藏super()去访问父类的无参构造
super();
System.out.println("子类的无参构造"); //输出:父类的无参构造 子类的无参构造
}
public Zi(String name) {
super(name); //通过使用super关键字去显示的调用父类的带参构造方法
System.out.println("子类的有参构造");
}
}
11.4.3 继承中成员方法的访问特点
this调用:在子类中访问一个变量,采用的是就近原则:
子类局部范围找
子类成员范围找
父类成员范围找
super调用:直接找父类
代码实例:
class Fu {
String name = "Fu";
}
class Zi extends Fu{
String name = "Zi";
public void show(){
//打印Zi
System.out.println(name);
System.out.println(this.name);
//打印Fu
System.out.println(super.name);
}
}
11.5 this & super
11.5.1 this
this & super 关键字
this:理解为一个变量,表示当前方法调用者的地址值
super:代表父类存储空间的标识(可以理解为父类对象的引用)
this & super 的使用区别
成员变量:
this.成员变量 -> 访问本类成员变量
super.成员变量 -> 访问父类成员变量
成员方法
this.成员方法 -> 访问本类成员方法
super.成员方法 -> 访问父类成员方法
构造方法
this(...) -> 访问本类构造方法
super(...) -> 访问父类构造方法
super内存图:
对象在堆内存中,会单独存在一块super区域,用来存放父类的数据
12. static相关
12.1 static关键字概述
static关键字是静态的意思,是Java中的一个修饰符,可以修饰成员方法,成员变量
12.2 static修饰的特点
static内存图示例:
被static修饰的成员变量,叫做静态变量
特点:
被该类所有对象共享,静态变量它的副本只有一个(静态变量在类中只加载一次)
不属于某个对象,属于类的
随着类的加载儿加载,优先于对象存在
调用方式:
类名调用
对象名调用
被static修饰的成员方法,叫做静态方法
调用方式:
类名调用
对象名调用
12.3 static的注意事项
静态方法只能访问静态变量和静态方法
不能访问非静态成员变量(实力变量)
不能访问非静态方法
非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法
静态方法中没有this关键字和super关键字。
示例代码
Student类
/*
静态随着类的加载而加载, 优先于对象存在
非静态需要在创建对象之后,才可以进行使用
1. 静态方法中, 只能访问静态成员(成员变量, 成员方法)
2. 非静态方法中, 可以使用静态成员, 也可以使用非静态成员
3. 静态方法中, 没有this关键字
*/
public class Student {
String name;
int age;
static String teacherName;
//this:表示当前方法调用者的地址值
//这个this:是由虚拟机赋值的
//this需要在创建对象之后, 才会存在, 静态存在的时候, 对象可能还没有被创建
//this.name = "张三";
public void show(Student this) {
System.out.println(name + "..." + age + "..." + teacherName);
}
public static void method(){
System.out.println(teacherName);
}
}
测试类
public class Test1Static {
/*
1. 被static修饰的成员, 会被该类的所有对象所[共享]
2. 被static修饰的成员, 会随着类的加载而加载, 优先于对象存在
3. 多了一种调用方式, 可以通过类名.进行调用
*/
public static void main(String[] args) {
Student.teacherName = "李四";
Student stu1 = new Student();
stu1.name = "张三";
stu1.age = 23;
//stu1.teacherName = "李四";
stu1.show();
Student stu2 = new Student();
stu2.show();
//调用静态方法
Student.method();
}
}
13. IO流相关
13.1 字符流&字节流
14. 方法的重写与重载
14.1 方法的重写
继承体系中,子类出现了和父类一模一样的方法声明,我们称子类这个方法是重写的方法
重写方法的名称、形参列表必须与父类中的一致
子类重写父类方法时,访问权限必须大于等于父类
子类重写父类方法时,返回值类型必须小于等于父类
只有被添加到虚方法表中的方法才能被重写
本质是子类覆盖了从父类继承下来的虚方法表里的方法
15. 类加载机制
15.1 类加载的过程
加载:主要是将.class文件中的二进制字节流读入到JVM中
通过一个类的全限定名来获取定义此类的二进制字节流
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
连接:包含验证、准备、解析
验证:确保加载进来的字节流符合JVM规范
文件格式验证
元数据验证,是否符合Java语言规范
字节码验证,确保程序语义合法,符合逻辑
符号引用验证,确保下一步的解析能正常运行
准备:为静态变量在方法区分配内存,并设置默认初始值
解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。
初始化:根据程序中的赋值语句主动为类变量赋值
什么时候需要初始化
使用new该类实例化对象的时候
读取或设置类静态字段的时候(但被final修饰的字段,在编译器时就被放入常量池的静态字段除外 static final)
调用类静态方法的时候
使用反射Class.forName(“xxx”)对类进行反射调用的时候,该类需要初始化
初始化一个类的时候,有父类,先初始化父类(注:1. 接口除外,父接口在调用的时候才会被初始化;2. 子类引用父类静态字段,只会引发父类初始化)
被标明为启动类的类(即包含main()方法的类)要初始化
当使用JDK1.7的动态语言支持时,如果一个java.invoke.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化
初始化顺序
父类的静态变量和静态代码块赋值(按照声明顺序)
自身的静态变量和静态代码块赋值(按照声明顺序)
父类成员变量和代码块赋值(按照声明顺序)
父类的构造器赋值:如果父类中包含有参构造器,却没有无参构造器,则在子类构造器中一定要使用“super(参数)”指定调用父类的有参构造器,不然就会报错
自身成员变量和代码块赋值(按照声明顺序)
自身构造器赋值
16. 正则表达式相关
16.1 字符类
语法示例:
格式 | 含义 |
[abc] | a、b、c字符中的一个 |
[^abc] | 除a、b、c以外的任何一个字符 |
[a-z] | a-z中任意一个小写字符 |
[A-Z] | A-Z中任意一个大写字符 |
[0-9] | 0-9中的任意一个数字字符 |
[a-zA-Z0-9] | a-z或者A-Z或者0-9中任意一个字符 |
[a-dm-p] | a-d或者m-p中任意一个字符 |
代码示例
public class RegexDemo {
public static void main(String[] args) {
//public boolean matches(String regex):判断是否与正则表达式匹配,匹配返回true
// 只能是a b c
System.out.println("-----------1-------------");
System.out.println("a".matches("[abc]")); // true
System.out.println("z".matches("[abc]")); // false
// 不能出现a b c
System.out.println("-----------2-------------");
System.out.println("a".matches("[^abc]")); // false
System.out.println("z".matches("[^abc]")); // true
System.out.println("zz".matches("[^abc]")); //false
System.out.println("zz".matches("[^abc][^abc]")); //true
// a到zA到Z(包括头尾的范围)
System.out.println("-----------3-------------");
System.out.println("a".matches("[a-zA-z]")); // true
System.out.println("z".matches("[a-zA-z]")); // true
System.out.println("aa".matches("[a-zA-z]"));//false
System.out.println("zz".matches("[a-zA-Z]")); //false
System.out.println("zz".matches("[a-zA-Z][a-zA-Z]")); //true
System.out.println("0".matches("[a-zA-Z]"));//false
System.out.println("0".matches("[a-zA-Z0-9]"));//true
// [a-d[m-p]] a到d,或m到p
System.out.println("-----------4-------------");
System.out.println("a".matches("[a-d[m-p]]"));//true
System.out.println("d".matches("[a-d[m-p]]")); //true
System.out.println("m".matches("[a-d[m-p]]")); //true
System.out.println("p".matches("[a-d[m-p]]")); //true
System.out.println("e".matches("[a-d[m-p]]")); //false
System.out.println("0".matches("[a-d[m-p]]")); //false
// [a-z&&[def]] a-z和def的交集。为:d,e,f
System.out.println("----------5------------");
System.out.println("a".matches("[a-z&[def]]")); //false
System.out.println("d".matches("[a-z&&[def]]")); //true
System.out.println("0".matches("[a-z&&[def]]")); //false
// [a-z&&[^bc]] a-z和非bc的交集。(等同于[ad-z])
System.out.println("-----------6------------_");
System.out.println("a".matches("[a-z&&[^bc]]"));//true
System.out.println("b".matches("[a-z&&[^bc]]")); //false
System.out.println("0".matches("[a-z&&[^bc]]")); //false
// [a-z&&[^m-p]] a到z和除了m到p的交集。(等同于[a-1q-z])
System.out.println("-----------7-------------");
System.out.println("a".matches("[a-z&&[^m-p]]")); //true
System.out.println("m".matches("[a-z&&[^m-p]]")); //false
System.out.println("0".matches("[a-z&&[^m-p]]")); //false
}
}
16.2 逻辑运算符
语法示例
格式 | 含义 |
&& | 并且 |
| | 或者 |
\ | 转义字符 |
代码示例
public class Demo {
public static void main(String[] args) {
String str = "had";
//1.要求字符串是小写辅音字符开头,后跟ad
String regex = "[a-z&&[^aeiou]]ad";
System.out.println("1." + str.matches(regex));
//2.要求字符串是aeiou中的某个字符开头,后跟ad
regex = "[a|e|i|o|u]ad";//这种写法相当于:regex = "[aeiou]ad";
System.out.println("2." + str.matches(regex));
}
}
public class RegexDemo3 {
public static void main(String[] args) {
// \ 转义字符 改变后面那个字符原本的含义
//练习:以字符串的形式打印一个双引号
//"在Java中表示字符串的开头或者结尾
//此时\表示转义字符,改变了后面那个双引号原本的含义
//把他变成了一个普普通通的双引号而已。
System.out.println("\"");
// \表示转义字符
//两个\的理解方式:前面的\是一个转义字符,改变了后面\原本的含义,把他变成一个普普通通的\而已。
System.out.println("c:Users\\moon\\IdeaProjects\\basic-code\\myapi\\src\\com\\itheima\\a08regexdemo\\RegexDemo1.java");
}
}
16.3 预定义字符
语法示例
格式 | 含义 |
. | 匹配任何字符 |
\d | 任何数字,[0-9]的简写 |
\D | 任何非数字,[ ^0-9]的简写 |
\s | 空白字符:[ \t\n\x0B\f\r] 的简写 |
\S | 非空白字符:[^\s] 的简写 |
\w | 单词字符:[a-zA-Z_0-9]的简写 |
\W | 非单词字符:[^\w]的简写 |
代码示例
public class Demo {
public static void main(String[] args) {
//.表示任意一个字符
System.out.println("你".matches("..")); //false
System.out.println("你".matches(".")); //true
System.out.println("你a".matches(".."));//true
// \\d 表示任意的一个数字
// \\d只能是任意的一位数字
// 简单来记:两个\表示一个\
System.out.println("a".matches("\\d")); // false
System.out.println("3".matches("\\d")); // true
System.out.println("333".matches("\\d")); // false
//\\w只能是一位单词字符[a-zA-Z_0-9]
System.out.println("z".matches("\\w")); // true
System.out.println("2".matches("\\w")); // true
System.out.println("21".matches("\\w")); // false
System.out.println("你".matches("\\w"));//false
// 非单词字符
System.out.println("你".matches("\\W")); // true
System.out.println("---------------------------------------------");
// 以上正则匹配只能校验单个字符。
// 必须是数字 字母 下划线 至少 6位
System.out.println("2442fsfsf".matches("\\w{6,}"));//true
System.out.println("244f".matches("\\w{6,}"));//false
// 必须是数字和字符 必须是4位
System.out.println("23dF".matches("[a-zA-Z0-9]{4}"));//true
System.out.println("23 F".matches("[a-zA-Z0-9]{4}"));//false
System.out.println("23dF".matches("[\\w&&[^_]]{4}"));//true
System.out.println("23_F".matches("[\\w&&[^_]]{4}"));//false
}
}
16.4 数量词
语法示例
格式 | 含义 |
X? | 0次或1次 |
X* | 0次或多次 |
X+ | 1次或多次 |
X{n} | 恰好n次 |
X{n,} | 至少n次 |
X{n,m} | n到m次(n和m都是包含的) |
代码示例
public class Demo {
public static void main(String[] args) {
// 必须是数字 字母 下划线 至少 6位
System.out.println("2442fsfsf".matches("\\w{6,}"));//true
System.out.println("244f".matches("\\w{6,}"));//false
// 必须是数字和字符 必须是4位
System.out.println("23dF".matches("[a-zA-Z0-9]{4}"));//true
System.out.println("23 F".matches("[a-zA-Z0-9]{4}"));//false
System.out.println("23dF".matches("[\\w&&[^_]]{4}"));//true
System.out.println("23_F".matches("[\\w&&[^_]]{4}"));//false
}
}