一、类变量与类方法
1.1 类变量快速入门
class Child{
private String name;
// 定义一个变量count,是一个类变量(静态变量)static 静态
// 改变量最大的特点就是会被Child类的所有对象实例访问
public static int count = 0;
public Child(String name){
this.name = name;
}
public void join(){
System.out.print(name + "加入了游戏");
}
}
-
注意:JDK1.8之前,静态变量在方法区中的
静态域
中;JDK1.8及之后,静态域存储于定义类型的Class对象
中,Class对象
如同堆中其他对象
一样,存在于GC堆中 -
记住一点:static变量是对象共享的,不管 static 变量在哪里,共识 (1) static 变量被同一个类所有对象共享 (2) static类变量,在类加载的时候就生成了
1.2 什么是类变量
类变量
是随着类的加载而创建的,所以即使没有创建对象实例也可以通过类访问
package com.codeblock;
public class CodeBlockDetail01 {
public static void main(String[] args) {
// AA被加载时,按顺序初始化类变量(n2 --> n1)
// out: 1. getN1被执行(初始化时的打印) 2. 200(调用类变量的返回)
System.out.println(AA.n2);
}
}
class AA{
public static int n2 = 200;
public static int n1 = getN1();
public static int getN1(){
System.out.println("getN1被执行");
return 100;
}
}
1.3 类变量使用注意事项和细节讨论
1.4 类方法基本介绍
1.5 类方法使用场景
1.6 类方法的注意事项和细节讨论
二、理解main方法 static
三、代码块
3.1 基本介绍
代码块
仅用于加载类
或创建对象
3.2 代码块使用注意事项和细节讨论
package com.codeblock;
public class CodeBlockDetail01 {
public static void main(String[] args) {
AA a = new AA(); // 执行静态代码块的内容
AA aa = new AA(); // 由于AA类已被加载,则不会执行静态代码块中的内容
}
}
class AA{
// 静态代码块
static{
System.out.println("AA的静态代码块1");
}
}
public class CodeBlickDetail2{
public static void main(String[] args){
// 类变量的显示初始化 与 静态代码块中的内容按顺序执行
// 属性的显示初始化 与 成员代码块中的内容按顺序执行
A a = new A(); // 1. getN1被执行... 2. 静态代码块被执行... 3. getN2被执行... 4. 普通代码块被执行...
}
}
class A{
private int n2 = getN2();
{
System.out.println("普通代码块被执行...");
}
public static int n1 = getN1();
static{
System.out.println("静态代码块被执行...");
}
public static int getN1(){
System.out.println("getN1被执行...");
return 100;
}
public static int getN2(){
System.out.println("getN2被执行...");
return 200;
}
}
class A{
public A(){ // 构造器
// 这里隐藏的执行要求
// (1) super();
// (2) 代用普通代码块与属性初始化
System.out.println("ok");
}
}
package com.codeblock;
public class CodeBlockDetail01 {
public static void main(String[] args) {
new BB();
}
}
class AA{
public int aa02 = getAa02();
{
System.out.println("AA code block 执行..."); // (6)
}
public int getAa02(){
System.out.println("getAa02执行..."); // (5)
return 200;
}
public static int aa01 = getAa01();
static {
System.out.println("AA static code block 执行..."); // (2)
}
public static int getAa01() {
System.out.println("getAa01执行..."); // (1)
return 1;
}
public AA(){
// 调用Object的构造器(略)
// 执行 代码块 与 属性初始化
System.out.println("AA 的构造器"); // (7)
}
}
class BB extends AA{
public int bb02 = getBb02();
{
System.out.println("BB code block 执行..."); // (9)
}
public int getBb02(){
System.out.println("getBb02执行..."); // (8)
return 100;
}
static {
System.out.println("BB static code block 执行..."); // (3)
}
public static int bb01 = getBb01();
public static int getBb01() {
System.out.println("getBb01执行..."); // (4)
return 10;
}
public BB(){
// 调用AA的构造器
// 执行 代码块 与 属性初始化
System.out.println("BB 的构造器"); // (10)
}
}
四、单例模式
- 什么是单例模式
五、final关键字
5.1 final的基本介绍
5.2 final使用注意事项和细节讨论
- 注意如果对方法的形式参数使用
final
,则在方法内部不能对该形参变量重新赋值;但是,如果是引用类型的形参变量被加了final
,是可以对其属性进行修改的 (本质是该局部变量的值一直都是引用变量的地址)
六、抽象类
6.1 抽象类的引入
abstract class Animal{
public String name;
public int age;
public Animal(String name, int age){
this.name = name;
this.age = age;
}
// 这里 eat 实现了,其实也没有什么意义
// 即:父类方法不确定性的问题
// ====> 考虑将该方法设计为抽象(abstract)方法
// ====> 所谓抽象方法就是没有实现的方法
// ====> 所谓没有实现就是指,没有方法体
// ====> 当一个类中存在抽象方法时,需要将该类声明为 abstract 类
// public void eat(){
// System.out.println();
// }
public abstract void eat();
}
6.2 抽象类基本介绍
- 抽象类使用的注意事项和细节讨论
// 对于上述第7点
abstract class E{
public abstract void hi();
}
// 继承抽象类的,第一种情况:可以不对抽象方法进行实现
abstract class F extends E{
}
// 继承抽象类的,第二种情况
abstract class G extends E{
public abstract void hi(){ // 重写了抽象类的方法
}
}
注意:Java中类方法不能被重写,而 抽象方法
存在的意义就是被子类重写
6.3 抽象类的最佳实践
七、接口
7.1 接口的引入
7.2 接口的基本介绍
package com.interface_;
public class TestInterface {
}
interface Interface{
// 属性强制是 public static final 修饰,可以不写
// 方法(除默认方法)强制是 public abstract 修饰,可以不写
// 默认方法是 public 修饰的
// 写属性,默认是 public static final 可以省略不写
public static final String str = "Hello";
// 写方法
// 在接口中,抽象方法,可以省略abstract关键字 和 public修饰符
void hi();
// 在jdk1.8后,可以有默认实现方法,需要使用 default关键字修饰
default void ok(){
System.out.println("ok ....");
}
// 在jdk1.8后,可以有静态方法
static void test1(){
}
}
7.3 接口的深度讨论
7.4 接口的注意事项和细节
- 注:
接口
之间是继承(支持多继承),类
和接口
之间是实现。
7.5 实现接口 vs 继承类
- 注:
接口
是对java单继承
的扩展。当子类继承了父类,就自动的拥有父类的功能。如果子类需要扩展功能,可以通过实现接口的方式扩展 - 更通俗的理解,
继承
主要使子类中拥有父类的方法,侧重于复用性
;接口实现
主要使类中实现
接口的抽象方法
侧重于重写
7.5 接口的多态特性
// 接口多态传递现象
public class InterfacePolyPass{
public static void main(String[] args){
IG ig = new Teacher(); // 接口引用可以指向
IH ih = new Teacher(); // 接口多态传递
}
interface IH{}
interface IG extends IH{} // 继承了 IH 接口
class Teacher implements IG{}
}
八、内部类
8.1 内部类基本介绍
- 类的五大属性:
属性
、方法
、构造器
、代码块
、内部类
8.2 局部内部类
- 在
方法体
或代码块
中定义的类
(常见的是在方法体中定义类)
package com.innerclass;
public class InnerTest {
public static void main(String[] args) {
Outer o = new Outer();
System.out.println(o.f1());
}
}
class Outer {
private int n1 = 1;
public int f1() {
class Inner { // 方法中的局部内部类
private int n1 = 1; // 与外部类的属性重名
private int n2 = 2;
public int getN2() {
return this.n2;
}
public void test() {
// 需要访问外部类的属性(与内部类中属性重名)
// Outer.this 的本质就是外部类的对象,即哪个对象调用了f1, Outer.this 就是哪个对象
System.out.println(Outer.this.n1);
}
}
Inner inner = new Inner();
inner.test();
return inner.getN2();
}
}
8.3 匿名内部类
package com.innerclass;
public class InnerAnonyClass {
public static void main(String[] args) {
Outer04 o = new Outer04();
o.method();
}
}
class Outer04 { // 外部类
private int n1 = 10;
public void method() {
// 基于接口的匿名内部类
// 解读
// 1. 需求:想使用IA接口,并创建对象
// 2. 传统方式,是写一个类,实现该接口,并创建对象
// 3. 老韩需求是 Tiger 类只是使用一次,后面再不使用
// 4. 可以使用匿名内部类来简化开发
// 5. tiger 的编译类型? IA
// 6. tiger 的运行类型? 就是匿名内部类 Outer04$1
/*
底层 会分配 类名 Outer04&1
class Outer04$1 implements IA {
@Override
public void call() {
System.out.println("老虎叫唤...");
}
}
*/
// 7. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
// 放回 tiger
// 8. 匿名内部类只能使用一次,就不能再使用(指的是该类的实例被加载进堆后,其类信息就被释放掉)
IA tiger = new IA() {
@Override
public void call() {
System.out.println("老虎叫唤...");
}
};
tiger.call();
// 演示基于类的匿名内部类
// 分析
// 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("jack") {
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
father.test();
// 基于抽象类的匿名内部类
Animal animal = new Animal() {
@Override
public void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
}
}
interface IA {
void call();
}
class Father {
private String name;
public Father() {
}
public Father(String name) {
this.name = name;
}
public void test() {
System.out.println("test...");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
abstract class Animal {
public abstract void eat();
}
8.3.1 匿名内部类的使用注意事项
8.3.2 匿名内部类的最佳实践
8.4 成员内部类
8.5 静态内部类
九、细节
9.1 static变量
-
注意:JDK1.8之前,静态变量在方法区中的
静态域
中;JDK1.8及之后,静态域存储于定义类型的Class对象
中,Class对象
如同堆中其他对象
一样,存在于GC堆中 -
记住一点:static变量是对象共享的,不管 static 变量在哪里,共识 (1) static 变量被同一个类所有对象共享 (2) static类变量,在类加载的时候就生成了
9.2 类变量与类方法
子类
是不继承父类的static变量和方法
的。因为这是属于类本身的。但是子类是可以访问的。子类
和父类
中同名的static变量和方法
都是相互独立的,并不存在任何的重写的关系。- 在多态的情况下调用
类变量
与类方法
均看均由编译类型
类方法
可以在同一类重载
public class Test{
public static void main(String args){
Base sub = new Sub();
System.out.print(sub.n); // 1
System.out.print(sub.getNum()); // 1
Sub s = new Sub();
System.out.print(s.n); // 2
System.out.print(s.getNum()); // 2
}
}
class Base{
public static int n = 1;
public static int getNum(){
return 1;
}
}
class Sub{
public static int n = 2;
public static int getNum(){
return 2;
}
}
9.3 类成员的初始化与实例对象成员的初始化
- 类成员:类变量、类方法
- 类变量:
- 可以显示赋值
public static String str = "1"
- 在
static 代码块
中
- 可以显示赋值
- 类方法:在随类的加载而被加载进方法区
- 类变量:
- 实例对象成员:属性和方法
- 属性:
- 可以显示赋值
- 在代码块中
- 在构造器中
- 属性:
9.4 接口在JDK 8 后的特性
package com.interface_;
public class TestInterface {
}
interface Interface{
// 属性强制是 public static final 修饰,可以不写
// 方法(除默认方法)强制是 public abstract 修饰,可以不写
// 默认方法是 public 修饰的
// 写属性,默认是 public static final 可以省略不写
public static final String str = "Hello";
// 写方法
// 在接口中,抽象方法,可以省略abstract关键字 和 public修饰符
void hi();
// 在jdk1.8后,可以有默认实现方法,需要使用 default关键字修饰
default void ok(){
System.out.println("ok ....");
}
// 在jdk1.8后,可以有静态方法
static void test1(){
}
}