学习内容
一、类变量和类方法
1.类变量
(1)基本介绍:
类变量(静态变量):类变量是该类所有对象共享的变量,任何一个类的对象去访问它是,取到的都是相同的值,同样任何一个该类的对象去修改它是,修改的也是同一个变量,加上static 为类变量或者静态变量。
语法格式:
- 访问修饰符 static 数据类型 变量名;【推荐】
- static 数据类型 变量名;
访问格式:
- 类名.类变量名;【推荐】
- 对象名.类变量名;
需要注意访问修饰符的权限
(2)使用细节
- 当某个类共享一个变量时,可以考虑使用类变量
- 类变量被该类的所有对象所共享,而普通变量(实例变量)是该类每个对象独享的
- 加static称为类变量或静态变量,否则称为实例变量
- 类变量可以通过,类.类变量名访问 或 类对象.类变量名访问,普通变量则不行
- 类变量在加载类时就已经初始化了
- 类变量的生命周期随着类的加载开始,随着类的消亡而销毁
public class test1 {
public static void main(String[] args) {
System.out.println(A.x); //正确10
System.out.println(new A().x); //正确10
// System.out.println(A.y); //错误
}
}
class A{
public static int x = 10; //静态变量
public int y = 20; //普通变量
}
2.类方法
(1)基本介绍:
类方法:又叫静态方法,与类变量类似
语法格式:
- 访问修饰符 static 数据返回类型 方法名(){ }【推荐】
- static 访问修饰符 数据返回类型 方法名(){ }
访问格式:
- 类名.类方法名();【推荐】
- 对象名.类方法名();
需要注意访问修饰符的权限
使用场景:
当方法中不涉及到任何对象的相关的成员时,则可以讲方法设置成静态方法,提高开发效率,即不创建对象也可以调用某个方法
(2)使用细节
- 类方法(静态方法)和普通方法都是随着类的加载而加载
- 类方法中无this的参数,普通方法中隐含着this的参数
- 类方法中不允许使用和对象有关的关键字,比如this和super。普通方法可以。
- 类方法中只能访问静态变量或静态方法,普通方法则都可以访问 前提:遵守访问修饰符权限
public class test1 {
public static void main(String[] args) {
// A.demo1(); //错误 private访问修饰符
A.test1();
// A.test(); //错误,该方法为普通方法
new A().test(); //创建对象可以调用普通方法
}
}
class A{
private static int x = 10; //静态变量
private int y = 20; //普通变量
private void demo(){}; //普通方法
private static void demo1(){}; //静态方法
//普通方法
public void test(){
System.out.println(this.y);
System.out.println(x+y); //普通和静态变量都可以访问
demo(); //可以访问普通方法
demo1(); //可以访问静态方法
}
//静态方法
public static void test1(){
// System.out.println(this.y); //错误 不可以使用this
// System.out.println(y); //错误 不能访问普通变量
// demo(); //错误 不能访问普通方法
System.out.println(x); //可以访问静态变量
demo1(); //可以访问静态方法
}
}
二、代码块
1.代码块
代码块:又称初始化块,属于类中的成员 即类的一部分,类似于方法,将逻辑语句封装在方法体重,通过{}包起来
与方法的区别:没有方法名、没有返回值、没有参数,只有方法体,不能通过对象或类显示调用,而是在类加载时,或者创建对象时隐士调用
使用场景:如果多个构造器中都有重复的语句,可以抽取到初始化代码块中,提高代码的复用性
基本格式:
[修饰符]{
代码;
}
修饰符只能是static,即代码块分为两类,带static称为静态代码块,不带static的称为普通代码块
代码块调用的顺序优先于构造器
2.使用细节☆
- 静态代码块就是在代码块前面加static,作用就是对类进行初始化,随着类的加载而执行,并且只会执行一次;而普通代码块每创建一个对象,就执行一次
- 类什么时候加载:
①创建对象实例时
②创建子类对象实例时,父类也会被加载
③使用类的静态成员时(静态属性,静态方法) - 如果使用类的静态成员时,普通代码块并不会执行
- 静态代码块和静态成员初始化调用优先级一样,普通代码块和普通成员初始化调用优先级一样
- 静态代码块只能调用静态成员,普通代码块可以调用任意成员
public class test1 {
public static void main(String[] args) {
// new A(); //对象被创建时,该类中的静态方法被调用
// new B(); //子类创建时,父类的静态方法也会被调用
System.out.println(A.a); //使用静态成员时,静态方法也会被调用
}
}
class A{
public static int a=10;
//注意:静态方法只会被执行一次
static {
System.out.println("A类静态代码块被调用!");
}
}
class B extends A{}
- 构造器的最前面,其实隐含了super()和调用普通代码块,也就是说在创建对象时 第一步调用了super 第二步就是调用普通代码块
public class test1 {
public static void main(String[] args) {
new A(); //输出:普通代码块 构造方法
}
}
class A{
//普通代码块
{
System.out.println("普通代码块");
}
public A(){
//super
//静态代码块
System.out.println("构造方法");
}
}
三、单例设计模式
1.基本介绍
设计模式:表示在大量的实践中总结和理论化之后优化选的代码结构、编程风格、以及解决问题的思考方式
单例模式:就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只能提供一个取得其对象实例的方法
单例模式分为两种:饿汉式和懒汉式
2.饿汉式
饿汉式步骤如下:
- 构造方法私有化(为了防止用户直接new)
- 在类内部创建一个static静态属性对象
- 向外提供一个静态的公共方法。如:public static Person getPerson(){}
public class test1 {
public static void main(String[] args) {
//类名调用静态方法getPerson()
Person person = Person.getPerson(); //构造器被调用
System.out.println(person); //自动调用toString方法
Person person1 = Person.getPerson(); //构造器只会被调用一次
System.out.println(person1); //自动调用toString方法
System.out.println(person.equals(person1)); //两者是同一个对象
}
}
class Person{
private String name;
//为了能在静态方法中,返回Person对象,则修饰符需要为static
private static Person Person= new Person("张三");
//private私有构造器类外就不能new创建对象
private Person(String name) {
this.name = name;
System.out.println("构造器被调用!");
}
//获取Person对象方法
public static Person getPerson() {
return Person;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
2.懒汉式
饿汉式步骤如下:
- 构造方法私有化(为了防止用户直接new)
- 在类内部创建一个static静态属性对象
- 向外提供一个静态的公共方法返回该对象
public class test1 {
public static void main(String[] args) {
//类名调用静态方法getPerson()
Person person = Person.getPerson(); //构造器被调用
System.out.println(person); //自动调用toString方法
Person person1 = Person.getPerson(); //构造器只会被调用一次
System.out.println(person1); //自动调用toString方法
System.out.println(person.equals(person1)); //两者是同一个对象
}
}
class Person{
private String name;
//为了能在静态方法中,返回Person对象,则修饰符需要为static
private static Person Person;
//private私有构造器类外就不能new创建对象
private Person(String name) {
this.name = name;
System.out.println("构造器被调用!");
}
//获取Person对象方法
public static Person getPerson() {
if (Person == null){
Person = new Person("张三");
}
return Person; //如果该对象不等于null则直接返回上次创建的对象
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
3.饿汉式和懒汉式的区别
- 两者创建对象的时机不同,饿汉式是在类加载时就创建了对象,而懒汉式是在使用时才创建
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
- 饿汉式存在浪费资源的可能,而懒汉式则不存在这问题,因为懒汉式在使用时对象才创建
四、final关键字
1.基本介绍
final:中文意思最终的,可以修饰类、属性、方法以及局部变量
使用场景:
- 当不希望类被继承时,可以用final修饰该类
- 当不希望父类的某个方法被 重写 或者 覆盖 时,可以用final修饰该方法
- 当不希望类的某个属性(全局变量)被修改时,可以用final修饰该属性
- 当不希望某个局部变量被修改时,可以用final修饰该变量
2.快速入门
public class test1 {
public static void main(String[] args) {
E e = new E();
// e.a = 20; //错误,因为属性(全局变量)a为final
}
}
//情况一
final class A{}
//class B extends A{} //错误,因为A类为final
class C{
public final void test(){}
}
//情况二
class D extends C{
//错误,因为父类方法test()为final
// @Override
// public void test() {
// super.test();
// }
}
//情况三
class E{
public final int a = 30;
}
//情况四
class F{
public void test(){
final int x = 20;
// x = 10; //错误,因为局部变量x为final
}
}
3.使用细节
- final修饰的属性在定义的时候,必须赋初始值,并且以后不能修改
- final修饰的属性时初始化的位置只能在
① 定义时赋值
② 在构造器外定义,在构造器中赋值
③ 在代码块外定义,在代码块中赋值 - 如果final修饰的属性是静态时,则初始化的位置只能在
① 定义时赋值
② 在静态代码块外定义,在静态代码块中赋值 - 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰程final方法
- final不能修饰构造方法
- final和static往往搭配使用,效率更高
- 包装类(Integer,Double,Float,Boolean等都是final),String也是final类
public class test1 {
public static void main(String[] args) {
A testA = new A();
System.out.println(testA.x+" "+testA.y+" "+testA.z+" "); //10 20 30
System.out.println(A.a+" "+A.b); //10 20
}
}
class A{
//非静态
public final int x = 10; //在定义时赋值
public final int y; //在构造器中赋值
public final int z;
//静态
public static int a = 10;
public static final int b;
//构造器
public A(){
y = 20;
}
//代码块
{
z = 30;
}
//静态代码块
static {
b = 20;
}
}
五、抽象类☆
1.基本介绍
抽象类:用abstract关键字修饰的类称为抽象类
语法格式:
访问修饰符 abstract 类名{ }
抽象方法:当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法
语法格式:
访问修饰符 abstract 返回类型 方法名( 参数列表 );
1.注意:抽象方法没有方法体
2.抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并事项抽象类
3.简化了代码的复杂性,提供代码的复用性
抽象类面试官比较爱问的知识点,在框架和设计模式使用较多
2.快速入门
定义抽象类和抽象方法
abstract class A{ //抽象类
String name;
int age;
abstract public void test(); //抽象方法
}
3.使用细节
- 抽象类不能被实例化
- 抽象类可以没有抽象方法,但抽象方法必须在抽象类中
- abstract 只能修饰类和方法,不能修饰属性和其它
- 抽象类中可以有除抽象方法外的其它属性、方法等
- 抽象方法不能有方法主体
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非这个类也声明为abstract 类
- 抽象方法不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的
public class test1 {
public static void main(String[] args) {
//细节1
// new A(); //错误
}
}
abstract class A{
String name;
int age;
abstract public void test();
//细节3
// abstract int x; //错误
//细节7
// abstract private void test1(); //错误
// final abstract void test2(); //错误
// abstract static void test3(); //错误
}
//细节2
class D{
// abstract public void test(); //错误
}
//细节6
class B extends A{
@Override
public void test() {
System.out.println("重写父类的抽象方法");
}
}
//细节6
abstract class C extends A{}
案例练习
public class test1 {
public static void main(String[] args) {
Manager manager = new Manager("张三", 10, 50000, 1000);
manager.work();
CommonEmployee employee = new CommonEmployee("李四", 20, 30000);
employee.work();
}
}
abstract class Employee{
String name;
int id;
int salary; //薪水
public Employee(String name, int id, int salary) {
this.name = name;
this.id = id;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public abstract void work(); //抽象类
}
class Manager extends Employee{
private double bonus; //奖金
public Manager(String name, int id, int salary, double bonus) {
super(name, id, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("经理 "+getName()+" 工作中~");
}
}
class CommonEmployee extends Employee{
public CommonEmployee(String name, int id, int salary) {
super(name, id, salary);
}
@Override
public void work() {
System.out.println("普通员工 "+getName()+" 工作中~");
}
}