测试代码:
public class TestCeShi {
public static void main(String[] args) {
TestSon s1 = new TestSon();
}
}
1. 静态 static
静态内部类、静态变量、静态常量(被static修饰过)
1.5 静态调用
定义静态变量、方法、内部类
public class StaticD {
private String name;
static int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void fun(){
System.out.println("guchao");
}
public void fun2(){
System.out.println("wanglei");
}
@Override
public String toString() {
return "StaticD{" +
"name='" + name + '\'' +
'}';
}
}
测试类:
public class DiaoYong {
public static void main(String[] args) {
//静态方法调用
StaticD.fun();
// 静态变量调用
StaticD.age = 15;
//普通方法调用
StaticD s1 = new StaticD();
s1.fun2();
//普通变量调用
s1.setName("guchao");
}
}
2. 单例模式
要求程序中某一个组件,在程序运行的整个生命周期,只有一个实例
构造函数私有,外面的组件不可以主动创建这个对象
1.构造函数私有,外面的组件不能主动创建这个对象
2.提供静态方法返回对象实例,返回的是静态实例
2.1 饿汉式单例模式:
在类健在时就被创建,无论是否使用。
构造函数素有,防止其他地方直接创建实例
实现简单、线程安全、任何时候都能保证只有一个实例存在
缺点是加载时间长,如果这个类一直没有使用会造成资源浪费
public class LanHan {
private LanHan() {
System.out.println("实例化");
}
//静态初始化,发生的最早
public static LanHan instance = new LanHan();
public static LanHan getInstance(){
return instance;
}
}
饿汉式
先初始化加载instance,并实例化个对象 指向堆里的内存地址。然后加载类,并调用getInstance,创建s1,返回instance。
2.2 懒汉式
没有静态初始化,等使用的时候在创建,实现了延迟加载,避免资源浪费
需考虑线程安全问题,如果多线程同时调用获取实例方法,并且实例未创建,可能导致多次创建
public class EEEhanshi {
private EEEhanshi() {
System.out.println("懒汉式实例化");
}
private static EEEhanshi instance = null;
public static EEEhanshi getInstance(){
if (instance == null){ //如果为空,创建新的实例对象,否则不用添加
instance = new EEEhanshi();
}
return instance;
}
}
懒汉式
public class HungryTest {
public static void main(String[] args) {
Hungry s1 = Hungry.getInstance();
Hungry s2 = Hungry.getInstance();
Hungry s3 = Hungry.getInstance();
Hungry s4 = Hungry.getInstance();
EEEhanshi s5 = EEEhanshi.getInstance();
EEEhanshi s6 = EEEhanshi.getInstance();
}
}
测试类
3. 代码块和初始化顺序
插 : 初始化
变量的初始化,具体取决于变量的类型和声明位置。
1.声明时赋初值:在声明变量的同时为其赋初值
2.构造函数初始化:对于类的实例变量,在对象创建时使用构造函数为其赋值
3.静态变量初始化:可以在生命是或者静态初始化块中进行初始化
4.默认初始化:如果没有显式初始化变量,则会进行默认初始化。数值类型的默认值为 0 或 0.0,布尔类型的默认值为 false,引用类型的默认值为 null。
java中,类的代码块分为静态(static block)和实例(instance block)代码块。
对象初始化顺序:
1.静态初始化
2.初始化
3.构造函数
4.父类先执行
3.1 案例
父类代码:
public class Test {
int i = 0; //默认初始化
{
System.out.println("初始化代码块");
}
{
System.out.println("初始化代码块2");
}
static int i2 = 0; //静态初始化
static{
System.out.println("静态初始化代码块");
}
static {
System.out.println("静态初始化代码块2");
}
public Test() {
System.out.println("父类初始化构造函数");
}
}
子类代码
public class TestSon extends Test{
int i = 0; //默认初始化
{
System.out.println("儿子初始化代码块");
}
{
System.out.println("儿子初始化代码块2");
}
static int i2 = 0; //静态初始化
static{
System.out.println("儿子静态初始化代码块");
}
static {
System.out.println("儿子静态初始化代码块2");
}
public TestSon() {
System.out.println("子类初始化构造函数");
}
}
案例执行顺序:
1.父类的静态初始化代码块
2.子类的静态初始化代码块
3.父类的初始化代码块
4.父类的构造函数
5.子类的初始化代码块
6.子类的构造函数
4. final关键词
public class FinalDemo {
// final void f1(){} //不能被重写
void f1(){}
}
class b extends FinalDemo{ //只能有一个public
//不能继承final类
final int age = 35;
@Override
void f1() {
// age = 36; age不能被改变
super.f1();
}
}
修饰类:不能被继承
修饰方法:不能被重写
修饰变量:不能被改变
5. 抽象类
抽象类是一种不能被实例化的类,用于作为其他类的父类或基类,可以包含抽象方法和具体类,用于定义子类共有的属性和行为。
- 抽象类不能被实例化,只能作为其他类的父类来使用。
- 抽象类可以包含抽象方法和具体方法。
- 抽象方法是没有具体实现的方法,只有方法签名。子类必须实现抽象方法。
- 具体方法是有具体实现的方法,子类可以直接继承和使用。
- 子类继承抽象类时,如果不实现所有的抽象方法,那么子类也必须声明为抽象类。
5.1 案例
public abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
// 抽象方法
public abstract void makeSound();
// 具体方法
public void sleep() {
System.out.println(name + " is sleeping.");
}
}
在上述代码中Animal是一个抽象类,定义了一个私有的String变量name,创建了构造函数Animal
包含一个抽象方法makesound 并且还有一个具体方法sleep 子类继承此父类时必须实现抽象方法:
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("Dog is barking.");
}
}
6. 接口
- 一方面, 有时必须从几个类中派生出一个子类, 继承它们所有的属性和方法。 但是, Java不支持多重继承。 有了接口, 就可以得到多重继承的效果。
- 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。 继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。
- 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
案例:
public interface Usb {
//接口的方法默认public abstract
public abstract void start();
void end();
//接口中不能有普通方法
// void f2() {
// }
}
public interface TypeC {
void transfer();
}
public class Printer implements Usb, TypeC {
@Override
public void start() {
System.out.println("usb 启动");
}
@Override
public void end() {
System.out.println("usb 关闭");
}
public void transfer() {
System.out.println("typeC接口传输数据");
}
}
6.1 接口和抽象类的区别:
1.接口不能有具体方法
2.接口可以实现多继承,抽象类不可以
3.接口方法默认public anstract
7. 内部类和匿名内部类
7.1 内部类(Inner class)
java中可以把一个类放到另一个类的内部,这个类就是内部类,下边是几种类型:
1.成员内部类(Menber Inner Class):定义在外部类的成员位置,与外部类的实例相关联,
可以访问外部类的所有成员(包括私有成员)
7.1.1 案例:
public class Person {
private String name;
private int age;
//内部类,如果一个类只给当前外部类使用,别的组件不用,比如Dog和Cat类只是在Person中使用
//所有的成员变量的修饰符,都可以修饰内部类
public static class Dog {
public void eat() {
System.out.println("狗吃骨头");
}
}
public class Cat {
public void eat() {
System.out.println("猫吃鱼");
}
}
public void f1() {
class Bird {
public void eat() {
System.out.println("鸟吃虫子");
}
}
Bird b = new Bird();
b.eat();
}
}
//测试类:
public class Test {
public static void main(String[] args) {
//创建静态成员内部类的方法
Person.Dog dog = new Person.Dog();
dog.eat();
//创建非静态成员内部类的方法
Person p = new Person();
Person.Cat cat = p.new Cat();
cat.eat();
p.f1();
}
}
7.2 匿名内部类(Anonymous Inner Class)
没有显式定义类的名称,而是通过new关键字来创建对象并覆盖
特点:
匿名内部类必须实现父类或实现接口
匿名内部类只能有一个对象
匿名内部类只能使用多态形式引用
语法:
7.2.1 案例
public class Test {
public static void f1(Usb usb) {
usb.start();
usb.end();
}
public static void f2(TypeC typeC) {
typeC.transfer();
}
public static void main(String[] args) {
// //内部类
// class Test$1 implements Usb {
// @Override
// public void start() {
// System.out.println("打印机usb启动");
// }
//
// @Override
// public void end() {
// System.out.println("打印机usb停止");
// }
// }
// Test$1 usb1 = new Test$1();
//方式1
/**
* 1:多态性:编译类型是父类
* 2:new 接口(类),后面跟一个实现
* 3:有一个对象usb1,实现了Usb接口的一个没有名字的类的实例
*
* Test$1->实现了Usb接口->用这个类产生一个对象usb1
*/
Usb usb1 = new Usb() {
@Override
public void start() {
System.out.println("打印机usb启动");
}
@Override
public void end() {
System.out.println("打印机usb停止");
}
};
f1(usb1);
//方式2:匿名内部类直接作为方法参数
f2(new TypeC() {
@Override
public void transfer() {
System.out.println("苹果14 正在传输数据....");
}
});
}
}
两种方法:
1.匿名内部类 创建对象并 加一个实现 Usb usb1 = new Usb { 实现Usb的抽象方法和抽象类}
后边用f1调用usb1对象。
2.匿名内部类直接作为方法参数 f2(new TypeC){ 实现TypeC的抽象方法}