思维导图概览:
1.什么叫做类变量/方法?
——给类中的成员属性或成员方法加上static关键字进行修饰,类变量/方法也叫做静态变量/方法,静态变量/方法被类的自身所有对象所共享使用
2.一个小case快速了解类变量/方法
public class Test {
public static void main(String[] args) {
//静态属性可以直接使用类名访问,也可以使用对象名访问,但是遵守访问权限
System.out.println(Animal.getAge());//18
Animal jack = new Animal("jack");
System.out.println(jack.getAge());//18
}
}
class Animal {
//成员变量
private String name;
//类变量
private static int age;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//静态方法
public static int getAge() {
age = 18;
return age;
}
}
3.类变量的内存布局
由图可知:
1)static变量(静态变量)被类的所有对象共享,这些对象均属于同一个类
2)静态变量,在类加载的时候就生成了
4.静态变量的定义和访问
1)静态变量的定义
i.访问修饰符 static 数据类型 变量名;(推荐)
ii.static 访问修饰符 数据类型 变量名;
2)静态变量的访问
i.类名.静态变量名(推荐)
ii.对象名.静态变量名
public class Test {
public static void main(String[] args) {
//访问静态变量的两种方式
//类名.静态变量名
//静态变量随着类的加载而创建,所有不需要使用创建对象去访问
System.out.println("姓名:" + Animal.name + "年龄:" + Animal.age);
//对象名.静态变量名
Animal animal = new Animal();
System.out.println("姓名:" + animal.name + "年龄:" + animal.age);
}
}
class Animal {
//静态变量的两种定义方式
//静态变量也需要遵守访问权限
public static String name = "大黄"; //推荐使用这种方式
static public int age = 18;
}
5.静态变量的细节讨论
1)什么时候需要使用静态变量?
当需要让所有对象都需要共享某一个变量的时候,那我们可以把这个变量设置为静态变量
2)静态变量和成员属性的区别
i.静态变量被同类的所有对象共享
ii.成员属性被每个对象独享,对象与对象之间的成员属性均独立
3)静态变量无需使用对象名访问,即没有创建对象,也能访问类变量
4)静态变量的生命周期随着类的加载而生成,随着类的销毁而消亡
public class Test {
public static void main(String[] args) {
//成员属性在每个对象之间均是独立的
Person jack = new Person("jack", 18);
Person marry = new Person("marry", 19);
//静态变量赋值
marry.setSalary(10000);
System.out.println(jack.getSalary());//10000
System.out.println(marry.getSalary());//10000
}
}
class Person {
//成员属性
private String name;
private int age;
//静态变量
public static char gender = '男';
//若是没有给静态变量赋值,应该提供一个set方法进行赋值
private static double salary;
//构造器
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//若是静态变量是私有的,那我们提供get/set进行赋值和取值
public void setSalary(double salary) {
//为了区分两个salary,静态变量使用类名.salary
Person.salary = salary;
}
public double getSalary() {
return Person.salary;
}
}
1.静态方法的定义和访问
1)静态方法的定义
i.访问修饰符 static 返回的数据类型 方法名(参数列表){};(推荐)
ii.static 访问修饰符 返回的数据类型 方法名(参数列表){};
2)静态方法的访问方式
i.使用类名.静态方法名访问
ii.使用对象.静态方法名
public class Test {
public static void main(String[] args) {
//静态方法的访问形式
//形式1:类名.静态方法名
Person.say();
Person.hi();
//形式2:对象名.静态方法名
Person person = new Person();
person.say();
person.hi();
}
}
class Person {
//静态方法的定义方式
//定义1:访问修饰符 static 返回的数据类型 方法名(形参列表) {}
public static void say() {
System.out.println("Hello,bro");
}
//定义2:static 访问修饰符 返回的数据类型 方法名(形参列表) {}
static public void hi() {
System.out.println("HI,bro");
}
}
2.静态方法的使用场景
——当方法中不涉及任何和对象相关的成员,则可以设置为静态方法
注:工具类中的方法均为静态方法,提高了开发效率
3.静态方法的细节讨论
1)静态方法的加载和普通成员方法的加载均是随着类的加载而加载的,将结构信息存储在方法区
2)静态方法中不能使用this和super关键字,为什么?
——因为静态方法不需要创建对象就能访问,而this和super关键字需要对象才能使用
public class Test {
public static void main(String[] args) {
Stu.say();
}
}
class Person {
public int age = 18;
}
class Stu extends Person {
//成员属性
private String name = "jack";
//构造器
public Stu() {
}
//静态方法中不能使用this和super关键字
public static void say() {
//System.out.println("name=" + this.name);
//System.out.println(super.age);
System.out.println("Hello,bro");
}
}
3)普通成员方法和静态方法的访问规则
i.普通方法能访问静态属性和普通成员属性
ii.静态方法只能访问静态属性
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.bye();
Person.hi();
}
}
class Person {
//注:方法和变量称为属性
//普通成员变量
private String name;
private int age;
//静态变量
private static double salary = 10000.0;
//普通成员方法
public void say() {
System.out.println("Hello");
}
//普通成员方法能访问静态属性和普通成员属性
public void bye() {
//普通成员属性
say();//普通方法
System.out.println(name);//普通成员
System.out.println(age);
//静态属性
hi();//静态方法
System.out.println(Person.salary);//静态变量
}
//静态方法只能访问静态属性
public static void hi() {
ok();//静态方法
System.out.println(Person.salary);//静态变量
//System.out.println(age);错误
}
public static void ok() {
System.out.println("Ok~");
}
}
思维导图概览:
1.什么是main方法?
——main方法是程序的主方法,一个程序只能有一个main方法,main方法是程序的入口
2.main方法的作用
——main方法的作用是为了Java虚拟机对程序的调用,main方法起了一个入口的作用
3.main方法的语法详解
public static void main(String[] args) {}
解释:
1)为什么需要pubic访问修饰符?
——因为Java虚拟机需要在类外调用main方法,所以main方法的访问权限必须是public
2)为什么需要static关键字?
——因为使用了static关键字后,我们不需要创建对象就能访问main方法
3)为什么需要使用void关键字?
——因为main方法我们不要求它给我们返回值,即是void
4)String[] args的作用是什么?
——String[] args接收命令行中的字符串
4.小tips
1)在main方法中,只能直接调用本类的静态属性,不能直接调用本类的非静态方法
2)不能直接调用的非静态属性,需要创建对象后访问
public class Test {
private int age = 18;
public static int sal = 10000;
public static void main(String[] args) {
//在main方法中可以直接访问静态属性
System.out.println(sal);
//main方法中需要创建对象后后才嫩访问成员属性
Test test = new Test();
System.out.println(test.age);
}
}
思维导图概览:
1.什么是代码块?
——代码块属于类中的成员,是类的一部分,类似于方法,代码块将逻辑语句使用{}包括起来;代码块没有方法名,返回参数,参数列表,只有方法体,不能通过类的显示调用,只能隐式使用
2.代码块语法
语法:
(修饰符) {
代码
};
注:
1)修饰符只有static可选
2)代码块分为静态代码块和普通代码块,静态代码块使用static修饰
3)代码块内可以写任何逻辑语句
4);号可写可不写
public class Test {
public static void main(String[] args) {
}
}
class Person {
//静态代码块
static {
System.out.println("静态代码块");
}
//普通代码块
{
System.out.println("普通代码块");
}
}
3.代码块的优点
1)相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化操作
2)如果多个构造器中有相同的语句,可以抽取到代码块中去进行初始化,可以完成代码的重用性
4.一个小case快速了解代码块
public class Test {
public static void main(String[] args) {
Person person = new Person("jack", 18);
}
}
class Person {
//成员变量
private String name;
private int age;
//静态代码块
static {
System.out.println("静态代码块");//静态代码块
}
//普通代码块
{
System.out.println("普通代码块");//普通代码块
}
//构造器
public Person(String name, int age) {
System.out.println("构造器器初始化~");//构造器器初始化~
this.name = name;
this.age = 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;
}
}
5.代码块的细节讨论
1)static修饰的代码块叫做静态代码块,作用是对类进行初始化,它随着类的加载而执行,只会执行一次
2)实例代码块的执行随着对象的创建就会执行,有几个对象则执行几次实例代码块
public class Test {
public static void main(String[] args) {
//创建了四个对象:静态代码块只会执行一次,普通代码块有几个对象则执行几次
//输出一次静态代码块,输出四次普通代码块
Person p = new Person();
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
}
}
class Person {
//静态代码块
static {
System.out.println("静态代码块");//静态代码块
}
//普通代码块
{
System.out.println("普通代码块");//普通代码块
}
}
3)类在什么时候进行加载?
i.创建对象实例的时候进行类的加载
ii.创建子类对象实例,父类也会被进行加载,先加载父类
iii.使用静态成员时进行类加载
public class Test {
public static void main(String[] args) {
//注:每个测试用例单独测试
//创建对象实例的时候进行类的加载
//Person person = new Person("jack",18);
//输出:父类的静态代码块~ 父类的普通代码块~ 父类的构造器~
//创建子类对象实例,先进行父类和子类的静态代码块,然后进行加载父类,再加载父类
//Stu stu = new Stu("marry",16);
//输出:父类的静态代码块~ 子类的静态代码块~ 父类的普通代码块~ 父类的构造器~ 子类的普通代码块~ 子类的构造器~
//使用静态成员时进行类加载
System.out.println(Stu.gender);
//输出:父类的静态代码块~ 子类的静态代码块~ 男
}
}
class Person {
//成员属性
private String name;
private int age;
//静态代码块
static {
System.out.println("父类的静态代码块~");
}
//普通代码块
{
System.out.println("父类的普通代码块~");
}
//构造器
public Person(String name, int age) {
System.out.println("父类的构造器~");
this.name = name;
this.age = 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;
}
}
class Stu extends Person {
//静态变量
public static char gender = '男';
public Stu(String name, int age) {
super(name, age);
System.out.println("子类的构造器~");
}
//静态代码块
static {
System.out.println("子类的静态代码块~");
}
//普通代码块
{
System.out.println("子类的普通代码块~");
}
}
4)在单个类中,创建一个对象时,类的调用顺序如下:
i.先调用静态成员初始化,静态代码块、静态属性的优先级一样,先定义的先调用
ii.然后调用普通代码块和普通成员属性初始化,优先级相同,先定义的先调用
iii.最后调用构造器
public class Test {
public static void main(String[] args) {
Person jack = new Person("jack", 18);
//输出:父类的静态代码块~ 父类的普通代码块~ 父类的构造器~
}
}
class Person {
//1)在类中先调用静态成员初始化,静态代码块、静态属性的优先级一样,先定义的先调用
//静态成员
public static char gender = '男';
//静态代码块
static {
System.out.println("父类的静态代码块~");
}
//2)调用普通代码块和普通成员属性初始化,优先级相同,先定义的先调用
//成员属性
private String name;
private int age;
//普通代码块
{
System.out.println("父类的普通代码块~");
}
//3)调用构造器
//构造器
public Person(String name, int age) {
System.out.println("父类的构造器~");
this.name = name;
this.age = 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;
}
}
5)构造器前面隐含了super和普通代码块的调用,执行顺序: super > 普通代码块 > 构造器
public class Test {
public static void main(String[] args) {
Stu stu = new Stu();
//输出:父类的普通代码块~ 父类的构造器~ 子类的普通代码块~ 子类的构造器~
}
}
//父类
class Person {
//代码块
{
System.out.println("父类的普通代码块~");
}
//构造器
public Person() {
System.out.println("父类的构造器~");
}
}
//子类
class Stu extends Person {
//代码块
{
System.out.println("子类的普通代码块~");
}
//构造器
public Stu() {
System.out.println("子类的构造器~");
}
}
6)当存在继承关系的时候,子类创建对象后,类的调用顺序为:
前提:成员 = 成员变量 + 成员方法
i.调用父类的静态成员对类进行初始化,若有多个静态成员,则按照定义顺序优先
ii.调用子类的静态成员对类进行初始化,若有多个静态成员,则按照定义顺序优先
iii.调用父类普通成员对类进行初始化,若有多个普通成员,则按照定义顺序优先
iv.调用父类的构造器
v.调用子类普通成员对类进行初始化,若有多个普通成员,则按照定义顺序优先
vi.调用子类的构造器
public class Test {
public static void main(String[] args) {
Stu stu = new Stu();
//输出:父类的静态代码块~ 子类的静态代码块~ 父类的普通代码块~ 父类的构造器~ 子类的普通代码块~ 子类的构造器~
}
}
class Person {
//代码块
static {
System.out.println("父类的静态代码块~");
}
{
System.out.println("父类的普通代码块~");
}
//构造器
public Person() {
System.out.println("父类的构造器~");
}
}
class Stu extends Person {
//代码块
static {
System.out.println("子类的静态代码块~");
}
{
System.out.println("子类的普通代码块~");
}
//构造器
public Stu() {
System.out.println("子类的构造器~");
}
}
7)静态代码块只能调用静态属性,普通代码块可以任意调用
public class Test {
public static void main(String[] args) {
}
}
class Person {
//静态成员变量
private static int id = 52213234;
//静态代码块
static {
//静态代码块只能调用静态成员
//say();//错误
hi();
System.out.println(id);
}
//普通代码块
{
//普通代码块能调用任意成员
System.out.println(Person.id);
say();
Person.hi();
}
//普通方法
public void say() {
System.out.println("普通say()方法~");
}
//静态方法
public static void hi() {
System.out.println("静态hi()方法~");
}
}