JavaSE知识重构
我亦无他,唯手熟尔。
参考:
B站【零基础 快速学Java】韩顺平 零基础30天学会Java
文章目录
- JavaSE知识重构
- 我亦无他,唯手熟尔。
- final关键字
- 需要使用final的需求:
- final注意细节
- 抽象类
- 接口
- 内部类
- 什么是内部类
- 内部类的特点
- 局部内部类的使用
- 匿名内部类的使用
- 成员内部类使用
- 静态内部类的使用
- 枚举和注解
- 枚举
- enum常用方法
- 注解
- 异常
- 常用类
- String类
final关键字
final可以修饰类、属性、方法和局部变量
需要使用final的需求:
- 类不可以被继承
- 父类的某个方法不可以被子类覆盖/继承(override)
- 类的某个属性值不可以被修改
- 某个局部变量不可以被修改
final注意细节
- final修饰的属性叫做常量,XXX_XXX_XXX来命名
- final修饰的属性在定义时,必须赋初值,并且之后不能修改。
赋值可以在如下位置:- 定义时
- 在构造器中
- 在代码块中
- 如果final修饰的属性是静态的,则初始化的位置只能是:
- 定义时
- 在静态代码块,不能在构造器中赋值
- final类不能继承,但可以实例化对象
- 如果类不是final类,但含有final方法,则该方法不能重写,但可以被继承。
- 如果一个类已经是final类了,没必要再将方法修饰成final方法
- final不能修饰构造方法(即构造器)
- final、static往往搭配使用,效率高,不会导致类加载(底层编译器做了优化处理)
- 包装类(Integer, Double, Float, Boolean等都是final),String类也是final类。
抽象类
exercise:
1、abstract final class A{}
能编译通过嘛?错误,final不能继承
2、abstract public static void test2();
能编译通过吗?错误,static关键字和方法重写无关。
3、abstract private void test3();
错误,私有的方法不能重写。
模板设计模式:
接口
内部类
类的五大成员:
属性、方法、构造器、代码块、内部类
什么是内部类
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。
内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
定义类在局部位置(方法中/代码块):(1)局部内部类(2)匿名内部类
定义在成员位置:(1)成员内部类(2)静态内部类
内部类的特点
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
- 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
- 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。
局部内部类的使用
局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
- 可以直接访问外部类的所有成员,包括私有的。
- 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
- 作用域:仅仅在定义它的方法或代码块中。
- 局部内部类–访问---->外部类成员 【访问方式:直接访问】
- 外部类–>访问—>局部内部类成员 【访问方式:创建对象,再访问(注意:必须在作用域内)】
注意:
1 局部内部类定义在方法中/代码块中
2 作用域再方法体或者代码块中
3 本质仍然是一个类 - 外部其他类–不能访问---->局部内部类(因为 局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(
外部类.this.成员
)去访问
public class LocalInnerClass {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.outer_02();
System.out.println("outer01的hashcode = " + outer01);
}
}
class Outer01{ //外部类
private int n1 = 100;
private void outer_f1(){
System.out.println("外部类实例方法");
}
public void outer_02(){ //方法
// 局部内部类是定义在外部类的局部位置上,通常在方法
// 不能添加访问修饰符,但是可以使用final修饰
// 作用域:仅仅在定义它的方法或代码块中
class Inner01{ //局部内部类(本质仍然是一个类)
private int n1 = 800;
public void inner_f1(){
// 局部内部类可以直接访问外部类的成员
// 如果外部类和内部类的成员重名,默认遵循就近原则
// 如果想访问外部类的成员 使用 外部类类名.this.成员 去访问
// Outer01.this 本质就是外部类的对象
System.out.println("n1 = " + n1);
System.out.println("外部类的n1 = " + Outer01.this.n1);
System.out.println("Outer01.this hashcode = " + Outer01.this);
}
}
Inner01 inner01 = new Inner01();
inner01.inner_f1();
}
}
n1 = 800
外部类的n1 = 100
Outer01.this hashcode = chapter10.innerclass.Outer01@1b6d3586
outer01的hashcode = chapter10.innerclass.Outer01@1b6d3586
匿名内部类的使用
1、本质是类
2、内部类
3、该类没有名字
4、同时还是一个对象
说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
匿名内部类的基本语法
new 类或接口(参数列表){
类体
}
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.method();
}
}
class Outer02{
//基于接口的匿名内部类
//1.需求: 想使用IA接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
//3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
//4. 可以使用匿名内部类来简化开发
//5. tiger的编译类型 ? IA
//6. tiger的运行类型 ? 就是匿名内部类 Outer04$1
/*
底层 会分配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
*/
//7. jdk底层在创建匿名内部类 Outer04$1,马上就创建了 Outer04$1实例,并且把地址
// 返回给 tiger
//8. 匿名内部类使用一次,就不能再使用
public void method(){
IA tiger = new IA(){
@Override
public void fun() {
System.out.println("老虎叫唤...");
}
};
System.out.println("tiger的运行类型 = " + tiger.getClass());
}
}
interface IA{
void fun();
}
tiger的运行类型 = class chapter10.innerclass.Outer02$1
匿名内部类可以访问外部类的所有成员,包含私有的。
不能添加访问修饰符,因为他的地位就是一个局部变量
作用域:仅仅在定义它的方法或者代码块中
外部其他类不能访问匿名内部类(因为匿名内部类地位是一个局部变量)
如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果访问外部类的成员,则可以使用(外部类名.this.成员)去访问。
//基于类的匿名内部类
//分析
//1. father编译类型 Father
//2. father运行类型 Outer04$2
//3. 底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
}
*/
//4. 同时也直接返回了 匿名内部类 Outer04$2的对象
//5. 注意("jack") 参数列表会传递给 构造器
Father father = new Father("tom"){
@Override
public void test() {
System.out.println("匿名内部类重写test方法");
}
};
System.out.println("father 对象的运行类型= " + father.getClass());
// father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal() {
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
System.out.println("animal对象的运行类型=" + animal.getClass());
animal.eat();
接收到的name=tom
father 对象的运行类型= class chapter10.innerclass.Outer02$2
animal对象的运行类型=class chapter10.innerclass.Outer02$3
小狗吃骨头…
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer03 outer03 = new Outer03();
outer03.f1();
//外部其他类---不能访问----->匿名内部类
System.out.println("main outer03 hashcode=" + outer03);
}
}
class Outer03{
private int n1 = 99;
public void f1() {
//创建一个基于类的匿名内部类
//不能添加访问修饰符,因为它的地位就是一个局部变量
//作用域 : 仅仅在定义它的方法或代码块中
Person p = new Person(){
private int n1 = 88;
@Override
public void hi() {
//可以直接访问外部类的所有成员,包含私有的
//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,
//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问
System.out.println("匿名内部类重写了 hi方法 n1=" + n1 +
" 外部内的n1=" + Outer03.this.n1 );
//Outer05.this 就是调用 f1的 对象
System.out.println("Outer03.this hashcode=" + Outer03.this);
}
};
p.hi();//动态绑定, 运行类型是 Outer03$1
//也可以直接调用, 匿名内部类本身也是返回对象
// class 匿名内部类 extends Person {}
new Person(){
@Override
public void hi() {
System.out.println("匿名内部类重写了 hi方法,哈哈...");
}
@Override
public void ok(String str) {
super.ok(str);
}
}.ok("jack");
}
}
class Person {//类
public void hi() {
System.out.println("Person hi()");
}
public void ok(String str) {
System.out.println("Person ok() " + str);
}
}
匿名内部类重写了 hi方法 n1=88 外部内的n1=99
Outer03.this hashcode=chapter10.innerclass.Outer03@1b6d3586
Person ok() jack
main outer03 hashcode=chapter10.innerclass.Outer03@1b6d3586
public class InnerClassExercise02 {
public static void main(String[] args) {
/*
1.有一个铃声接口Bell,里面有个ring方法。(右图)
2.有一个手机类Cellphone,具有闹钟功能alarmClock,参数是Bell类型(右图)
3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
4.再传入另一个匿名内部类(对象),打印:小伙伴上课了
*/
CellPhone cellPhone = new CellPhone();
//老韩解读
//1. 传递的是实现了 Bell接口的匿名内部类 InnerClassExercise02$1
//2. 重写了 ring
//3. Bell bell = new Bell() {
// @Override
// public void ring() {
// System.out.println("懒猪起床了");
// }
// }
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
interface Bell{ //接口
void ring();//方法
}
class CellPhone{//类
public void alarmClock(Bell bell){//形参是Bell接口类型
System.out.println(bell.getClass());
bell.ring();//动态绑定
}
}
成员内部类使用
成员内部类是定义在外部类的成员位置,并且没有static修饰。
1、可以直接访问外部类的所有成员,包括私有的。
2、可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
3、作用域:和外部类的其他成员一样,为整个类。
4、成员内部类–访问---->外部类成员(属性)【访问方式:直接访问】
5、外部类–访问---->成员内部类【访问方式:创建对象,再访问】
6、外部其他类–访问---->成员内部类
7、如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果访问外部类的成员,则可以使用(外部类.this.成员)去访问
静态内部类的使用
静态内部类是定义在外部类的成员位置,并且有static修饰
1、可以直接访问外部类的所有静态成员,包括私有的,但不能直接访问非静态成员。
2、可以添加任意访问修饰符(public、protected、默认、private),因为他的地位就是一个成员
3、作用域:同其他成员,为整个类
4、静态内部类–访问---->外部类(比如:静态属性)【访问方式:直接访问所有静态成员】
5、外部类–>访问---->静态内部类【访问方式:创建对象,再访问】
6、外部其他类–>访问---->静态内部类
7、如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵循就近原则,如果访问外部类的成员,则可以使用(外部类名.成员)去访问
public class StaticInnerClass01 {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.m1();
// 外部其它类 使用静态内部类
// 方式一
Outer05.Inner05 inner05 = new Outer05.Inner05();
inner05.say();
// 方式2
// 编写一个方法,可以返回静态内部类的对象实例
Outer05.Inner05 inner051 = outer05.getInner05();
inner05.say();
Outer05.Inner05 inner05_ = Outer05.getInner05_();
inner05.say();
}
}
class Outer05{
private int n1 = 10;
private static String name = "张三";
private static void cry(){};
//Inner05就是静态内部类
//1. 放在外部类的成员位置
//2. 使用static 修饰
//3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
//4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
//5. 作用域 :同其他的成员,为整个类体
static class Inner05{
private static String name = "我亦无他,唯手熟尔。";
// 如果外部类和静态内部类的成员重名时,静态内部类访问的时候
// 默认遵循就近原则,如果访问外部类的成员,则可以使用(外部类名.成员)
public void say(){
System.out.println(name + " 外部类name = " + Outer05.name);
// 静态内部类直接使用外部类的静态方法
cry();
}
}
//外部类---访问------>静态内部类 访问方式:创建对象,再访问
public void m1(){
Inner05 inner05 = new Inner05();
inner05.say();
}
public Inner05 getInner05(){
return new Inner05();
}
public static Inner05 getInner05_(){
return new Inner05();
}
}
枚举和注解
枚举
1、使用enum关键字实现枚举类,默认继承Enum类,而且是一个final类
2、如果使用无参构造器创建枚举对象,则实参列表和小括号可以省略
3、当有多个枚举对象时,使用逗号间隔,最后有一个分号结尾。
4、枚举对象必须放在枚举类的行首
public class Enumeration03 {
public static void main(String[] args) {
System.out.println(Season2.AUTUMN);
System.out.println(Season2.SUMMER);
}
}
//演示使用enum关键字来实现枚举类
enum Season2 {//类
//定义了四个对象, 固定.
// public static final Season SPRING = new Season("春天", "温暖");
// public static final Season WINTER = new Season("冬天", "寒冷");
// public static final Season AUTUMN = new Season("秋天", "凉爽");
// public static final Season SUMMER = new Season("夏天", "炎热");
//如果使用了enum 来实现枚举类
//1. 使用关键字 enum 替代 class
//2. public static final Season SPRING = new Season("春天", "温暖") 直接使用
// SPRING("春天", "温暖") 解读 常量名(实参列表)
//3. 如果有多个常量(对象), 使用 ,号间隔即可
//4. 如果使用enum 来实现枚举,要求将定义常量对象,写在前面
//5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()
SPRING("春天", "温暖"), WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"),
SUMMER("夏天", "炎热")/*, What()*/;
private String name;
private String desc;//描述
private Season2() {//无参构造器
}
private Season2(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
enum常用方法
toString
:Enum 类已经重写过了,返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息name
:返回当前对象名(常量名),子类中不能重写ordinal
:返回当前对象的位置号,默认从0 开始values
:返回当前枚举类中所有的常量valueOf
:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常!compareTo
:比较两个枚举常量,比较的就是编号!- 使用enum 关键字后,就不能再继承其它类了,因为enum 会隐式继承Enum,而Java 是单继承机制。
- 枚举类和普通类一样,可以实现接口
注解
异常
常用类
String类
hsp and hava
。。