static是一个修饰符,表示静态的意思,可以修饰属性、方法、代码块。它的主要作用是使得这些语法结构不再与对象实例相关,而是属于类本身,从而可以在不创建对象的情况下进行访问和调用。
static修饰类中的数据成员,该成员就成了静态数据成员,也称为类成员;类成员,是属于类的,为这个类所有对象共享,只占用一块内存空间。它们的值可以被所有对象共享。静态变量在类加载时就已经被初始化,而且只会被初始化一次,直到程序结束或类被卸载。
class Student {
public static int num;
}
public static void main(String[] args) {
//可以使用类名来访问,推荐用法
Student.num = 10;
Student stu = new Student();
//也可以对象来访问,但不推荐
stu.num = 20;
}
package 包名;
/**
* @author 谭梦寻
* @version 1.1
*/
class Demo {
public static int num;
}
public class TestStatic {
public static void main(String[] args) {
//1.静态数据成员会随着类的加载而加载(开辟内存并进行默认初始化)
//先于对象存在
Demo.num = 10;
//2.实例化两个对象,然后通过对象访问静态成员,输出其值
Demo demo1 = new Demo();
Demo demo2 = new Demo();
System.out.println(demo1.num);//输出结果为 10
System.out.println(demo2.num);//输出结果为 10
/* 可以看出,无论是使用类访问静态属性,还是使用这个类的某个对象访问静属性,
效果是一样的,这个属性对这个类的所有对象都是可见的、共享的。
静态属性的存储位置:
在方法区中有一块静态区,专门用来存储各个类静态数据成员。
当操作静态数据成员时,不论是通过类名,还是通过对象名操作,
都是操作静态区中对应的内存区域。
*/
//3.通过类名修改静态成员值,再借助对象.static成员,输出其值
Demo.num = 20;
System.out.println(demo1.num);//输出结果为 20
System.out.println(demo2.num);//输出结果为 20
//4.通过对象名修改静态成员值,再借助类名.static成员,输出其值
demo1.num = 30;
System.out.println(Demo.num);//输出结果为 30
System.out.println(demo2.num);//输出结果为 30
}
}
在方法区中有一块静态区,专门用来存储各个类静态数据成员。当操作静态数据成员时,不论是通过类名,还是通过对象名操作,都是操作静态区中对应的内存区域 。
在类中,使用static修饰的方法,就是静态方法。和静态变量一样,静态方法属于类本身,而不是对象实例。因此,静态方法可以直接通过类名来调用,而不需要先创建一个对象。
static方法的作用,主要是用来操作static成员;
class Demo {
public static int num;
public static void method() {
System.out.println("这是一个静态方法");
}
}
public class TestStatic {
public static void main(String[] args) {
//1.静态方法会随着类的加载而加载(开辟内存并进行默认初始化)
//先于对象存在
Demo.method();
Demo.num = 10;
//2.实例化对象,然后通过对象访问静态方法
Demo demo1 = new Demo();
demo1.method();
//两者执行的结果是一样的
}
}
案例:
//学校类
class School {
private String name; //名称
private int num; //师生数量
//用private修饰static成员,则该类外无法直接访问该static成员
private static String library = "栋梁图书馆";
//定义public修饰的static方法,专门来操作static成员
public static String getLibrary() {
//注意1:static方法中没有this
//return this.library; //error
//注意2:static方法中不可以访问普通数据成员
//name = "一高"; //error
return library;
}
}
//测试方法
public static void main(String[] args) {
//1.在创建School对象前,输出 static成员值
//编译报错,library为private,只能School类内访问
//System.out.println(School.library);
//2.借助类名调用static方法,推荐用法
String lib = School.getLibrary();
System.out.println(lib);
//3.借助方法名调用static方法,不推荐
School s1 = new School("第一中学",3000);
System.out.println(s1.getLibrary());
}
在Java中,使用 { } 括起来的代码被称为代码块,具体可以分为以下三类:
案例:
public class Test0104_LocalBlock {
public static void main(String[] args) {
//局部代码块
{
int a = 10;
System.out.println(a);
}
//上面局部代码块中的a是局部变量,遇到 } 其占用的内存空间就销毁了
//下面输出语句编译报错
//System.out.println(a);
}
}
案例:
package com.briup.day07;
/**
* @author 谭梦寻
* @version 1.1
*/
public class TestConsBlock { //测试类
public static void main(String[] args) {
//实例化2个对象,观察程序输出效果:
//每次构造方法执行前,都会自动执行构造代码块
Module m1 = new Module();
Module m2 = new Module(10);
}
}
//基础类
class Module {
private int num;
//构造|匿名代码块
{
System.out.println("构造代码块: 构造方法执行前执行...");
}
//无参构造方法
public Module() {
System.out.println("Module() ...");
}
//有参构造方法
public Module(int num) {
System.out.println("Module(int) ...");
this.num = num;
}
}
案例:
class Teacher {
// 属性
private int id;
// 静态属性
private static String school;
// 代码块
static {
// 静态代码块
school = "希望小学";
System.out.println(school);//输出 希望小学
}
{
// 非静态代码块
this.salary = 3000;
}
}
加载类的含义:JVM虚拟机将该类的class文件加载到内存的方法区中。
当Java代码中用到某个类的时候,就会加载该类。
案例:基础类
public class School {
private String name;
private static String library = "辽东图书馆";
private int num;
{
// 没有名字的代码块 只能创建对象时 自动调用
// 构造(创建对象)代码块 构造器 构造方法
System.out.println("构造代码块");
}
static {
// 静态代码块只加载一次:类加载只加载一次 jvm机只需要一次将该类加载
System.out.println("静态代码块");
// this不能放在静态代码块中
// 创建对象
// School school = new School();//可以
}
public School() {
}
public School(String name, int num) {
this.name = name;
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLibrary() {
return library;
}
public void setLibrary(String library) {
School.library = library;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public static void method() {
// 静态方法不能访问非静态属性 --》 类的加载机制 先加载类的信息,后对象信息
// 静态信息优先加载 故非静态属性和方法还未加载 不能直接访问
// 非静态方法可以访问静态方法和静态属性,当然 其他非静态的也能访问
// 静态方法中没有this关键字 this是对象,静态方法是类名调用 刚加载时没有对象 虽然也能通过对象访问,但不推荐
// System.out.println(num);//不能直接访问
System.out.println("这是一个静态方法");
}
@Override
public String toString() {
return "School{" +
"name='" + name + '\'' +
", num=" + num +
'}';
}
}
测试类:
public class TestSchool {
public static void main(String[] args) {
School school = new School("莲塘一中", 3000);
System.out.println(school.getLibrary());
// school.library //报错 私有属性不能直接访问
school.method();//不推荐
School.method();
School school1 = new School();
}
}
结果:
代码加载过程:先是静态,然后是非静态,最后是构造器。
类和类之间的关系有很多中,继承就是其中一种关系,通过关键字extends实现。
[public] class 子类名 extends 父类名 {
子类新增内容;
}
案例:
/**
* 继承了 Object(Object类没有父类 其他的都有父类,也都可以成为子类)
* 任何类都继承了java.lang.Object(根基类)
* 继承可以提高代码的复用性(不重复定义方法 使用父类的方法)
*/
public class Father {//extends Object
public int a;
private int b;
private void test() {
System.out.println("test");
}
public static void method1() {
System.out.println("这是父类的静态方法");
}
public void testA() {
System.out.println("testA");
}
}
class Son extends Father{
// 子类只能继承父类所有非私有方法和属性
public void method() {
System.out.println(a);//0
// System.out.println(b); //私有属性不可继承 故不可使用
}
public static void main(String[] args) {
Son son = new Son();
son.method();//输出0
// 静态方法也能被继承
son.method1();//这是父类的静态方法
System.out.println(son.toString());//继承了object中的toString()方法
}
}
当从父类继承的非private成员,和子类新增的成员重名时,借助super关键字可以区分两个成员 。
super表示子类继承父类的那部分。
代码展示:
public class Father {
public int id;
public Father() {
System.out.println("父类构造器");
}
public Father(int id) {
this.id = id;
}
public static void method1() {
System.out.println("这是父类的静态方法");
}
public static void main(String[] args) {
// 当子类对象被创建时 (默认)会自动调用父类的无参构造器
Son son = new Son();
System.out.println(son);
Son jack = new Son("jack", "北京");
System.out.println(jack);
Son joker = new Son("joker", "北京",1);
System.out.println(joker);
son.method1();
// joker.method();
}
}
class Son extends Father{
private String name;
private String city;
public Son() {
super();//显式地调用父类的无参构造器 可以不写,系统默认有
System.out.println("子类构造器");
}
// @Override
private void method() {
System.out.println("Son");
}
public Son(String name, String city) {
this.name = name;
this.city = city;
}
public Son(String name, String city,int id) {
super(id); //super调用父类构造器一定要放在第一行
this.name = name;
this.city = city;
// this.id = id;//或者super.id = id
}
@Override
public String toString() {
return "Son{" +
"id=" + id +
", name='" + name + '\'' +
", city='" + city + '\'' +
'}';
}
}