目录
1. static
- 使用范围:可用static修饰属性,方法,代码块,内部类
- 被修饰后的成员具备以下特点:
- 随着类的加载而加载
- 优先于对象存在
- 修饰的成员,被所有对象所共享
- 访问权限允许时,可不创建对象,直接被类调用
- 类方法,类中使用static修饰的方法
- 没有对象的实例时,可以用类名.方法名()的形式访问由static 修饰的类方法
- 在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构
- 因为不需要实例就可以访问static方法,因此static方法内部不能有this和super
- static修饰的方法不能被重写
//探究static的使用和准则
public class Chinese {
private String name;
private int age;
public static String nation = "大中国";//静态变量
public void f1(){
System.out.println("f1()");
}
public static void f2(){
System.out.println("f2()");
}
public static void show(){
System.out.println("自我介绍" + nation);
f2();
}
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 class Test1 {
public static void main(String[] args) {
Chinese malong = new Chinese();
malong.setAge(32);
malong.setName("马龙");
malong.nation = "中华人民共和国";
Chinese yaoming = new Chinese();
yaoming.setAge(34);
yaoming.setName("姚明");
yaoming.nation = "中国";
System.out.println(malong.getName());
System.out.println(malong.nation);//一般不这么用,静态方法直接使用:类名 + 成员名
System.out.println(Chinese.nation);
Chinese.show();//静态方法
}
}
1.1 static的流程图
2. 单例模式
单例模式:要求程序中某一组件,在程序运行的整个生命周期中,只有一个实例
单例模式有两种:饿汉式,懒汉式
步骤如下:
- 构造函数私有化,外面的组件不能主动创建这个对象
- 提供静态方法返回对象实例,返回的是静态实例,所以只有一个实例
2.1 饿汉式
- 好处:线程安全
- 坏处:加载时,时间比较长
2.2 懒汉式
存在线程安全问题,没有静态初始化
饿汉式://探究单例模式
public class HungerSingleton {
private HungerSingleton() {//构造函数私有化
System.out.println("HungerSingleton初始化...");
}
private static HungerSingleton instance = new HungerSingleton();//在方法区新建一个对象
public static HungerSingleton getInstance() {//静态方法,返回实例对象
return instance;
}
}
懒汉式:
public class LazySingleton {
private LazySingleton() {//构造函数私有化
System.out.println("LazySingleton被调用...");
}
private static LazySingleton instance = null;//实例对象先设为空,如果要使用在new
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
测试部分
public class Test1 {
public static void main(String[] args) {
//饿汉式
HungerSingleton s1 = HungerSingleton.getInstance();//调用HungerSingleton的静态方法getInstance
HungerSingleton s2 = HungerSingleton.getInstance();
HungerSingleton s3 = HungerSingleton.getInstance();
//懒汉式:在方法区懒得初始化,所以叫懒汉式
LazySingleton n1 = LazySingleton.getInstance();//调用LazySingleton的静态方法getInstance
LazySingleton n2 = LazySingleton.getInstance();
LazySingleton n3 = LazySingleton.getInstance();
}
}
2.3 饿汉式JMM状态
3. 代码化和初始化顺序
顺序:
- 静态初始化(先进行父类的初始化,再进行子类初始化)
- 父类代码块初始化、构造函数
- 子类代码块初始化、构造函数
//探究代码块和初始化顺序
public class Paent {
public int i = 10;//初始化
{//代码块
System.out.println("parent初始化代码块1");
}
{//代码块
System.out.println("parent初始化代码块2");
}
public static int i2 = 0;//静态初始化
static{//静态代码块
System.out.println("parent静态初始化代码块1");
}
static{//静态代码块
System.out.println("parent静态初始化代码块2");
}
public Paent() {
System.out.println("parent构造函数。。。");
}
}
/*初始化顺序
1.静态初始化
2,初始化代码、构造函数。
如果有父类,先进行 父类静态-->子类静态 -->父类初始化代码块、构造函数-->子类初始化代码块、构造函数
*/
public class Children extends Paent {
public int i = 20;
{//代码块
System.out.println("Children初始化代码块1");
}
{//代码块
System.out.println("Children初始化代码块2");
}
static{//静态代码块
System.out.println("Children静态初始化代码块1");
}
static{//静态代码块
System.out.println("Children静态初始化代码块2");
}
public Children() {
System.out.println("Children构造函数。。。");
}
public static void main(String[] args) {
Children children = new Children();
}
}
4. final关键字
- 修饰类:表示类不能被继承
- 修饰方法:表示方法不能被重写
- 修饰成员变量:表示变量不能被改变
//探究关键词final
public class Test {
public static void main(String[] args) {
}
}
class A { //final修饰的类不能被继承
// public final void f1(){}; //final修饰的方法不能被重写
public void f1() {
}
}
class B extends A {
public final int i = 1;
@Override
public void f1() {
// i = 20; //final修饰的属性不能被改变
}
}
5. 抽象类
- 用abstract关键字来修饰一个类,这个类叫做抽象类。
- 用abstract来修饰一个方法,该方法叫做抽象方法。抽象方法:只有方法的声明,没有方法的实现。如
public abstratc void talk();
注意没有大括号 - 含有抽象方法的类必须声明为抽象类
- 抽象类不能被实例化,只能用来继承,子类重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类
//探究抽象类的特性
public abstract class A {//声明抽象类
public abstract void f1();//抽象方法
public void f2() {//抽象类中可以写非抽象的方法
System.out.println("这是一个f2()方法。。。");
}
}
public class B extends A {
@Override
public void f1(){//实现抽象类中的抽象方法
System.out.println("实现抽象类的f1()方法。。。");
}
}
//测试
public class Test {
public static void main(String[] args) {
// new A();//不能实例化抽象类
B b = new B();//实例化抽象类的子类实现父类的抽象方法
}
}
6. 接口
- 有了接口, 就可以得到多重继承的效果。
- 它们之间又没有is-a的关系,但是具有相同的行为特征。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、 MP3机、手机、数码相机、移动硬盘等都支持USB连接。
- 继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。
public interface Usb {
//接口方法默认有public abstract
public void start();
public void end();
//接口中不能有非抽象方法,只能存在抽象方法
// public void f1(){}; 报错
}
public interface TypeC {
void transfer();
}
public class Printer implements Usb, TypeC {//接口能实现多继承,抽象类不能
@Override
public void transfer() {
System.out.println("TypeC接口传输数据");
}
@Override
public void start() {
System.out.println("Usb接口启动");
}
@Override
public void end() {
System.out.println("Usb接口关闭");
}
}
6.1 接口与抽象类
- 抽象类可以有非抽象方法,接口只能有抽象方法
- 接口中方法默认带
public abstract
- 接口可以实现多继承,抽象类不可以
7. 内部类(了解)
将一个类放在另一个类的内部,这个类就叫做内部类
内部类的分类:
- 在成员变量的位置
- static成员内部类
- 非静态的成员内部类
- 在方法中的某个位置:局部内部类
语法:
- 修饰成员变量的所有的修饰符都可以修饰成员内部类
- 部类可以使用继承
//探究内部类的使用
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();
}
}
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 bird = new Bird();
bird.eat();
}
}
8. 匿名内部类
- 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
- 匿名内部类的特点
- 匿名内部类必须继承父类或实现接口
- 匿名内部类只能有一个对象
- 匿名内部类对象只能在使用多态形式引用
语法:
接口 变量名 = new 接口 {
重写的代码
}
案例如下:
package test8;//探究匿名内部类的使用和原则
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) {
//方法1:
/*
1.多态性:编译类型时父类
2.new接口,后面跟一个实现
3.有一个对象usb1,实现了Usb接口的一个没有名字的类的实例
*/
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正在传输数据...");
}
});
}
}
public interface TypeC {
void transfer();
}
public interface Usb {
//接口方法默认有public abstract
public void start();
public void end();
//接口中不能有非抽象方法,只能存在抽象方法
// public void f1(){}; 报错
}