Java中static是什么?作用是什么?如何使用? ——关键字static
static
概述
静态的意思
可以修饰的内容
(1) 成员变量
(2) 成员方法
(3) 代码块
修饰成员变量
概述: static 修饰的成员变量称为 静态变量 类变量 静态属性
成员变量: 定义在类的成员位置的变量
实例变量: 就是现在说的成员变量 ---> 非静态变量
静态变量: 被static 修饰的实例变量 ----> 静态变量
在实际的开发中不会特意的区分 实例变量 和 静态变量,经常使用成员变量来默认表示实例变量
语法:
访问修饰符 static 数据类型 变量名 = 变量值;
static 访问修饰符 数据类型 变量名 = 变量值;
特点:
- 被所有对象共享
- 可以使用 类名.属性名访问
- 也可以通过对象的引用进行访问 (不推荐)
案例:
//案例1: 关于特点1
public class Demo2 {
public static void main(String[] args) {
//创建两个对象 ---> test1 test2 是两个独立的对象 每个对象中都有自己的 a b
Test1 test1 = new Test1();
Test1 test2 = new Test1();
test1.a++;
test1.b++;
test1.c++;
System.out.println(test1.a);//11
System.out.println(test1.b);//21
System.out.println(test1.c);//31
System.out.println(test2.a);//10
System.out.println(test2.b);//2
System.out.println(test2.c);
Test1 test3 = new Test1();
System.out.println(test3.c);
}
}
class Test1{
// 定义一个成员变量
int a = 10;
int b = 20;
// 定义一个静态变量
static int c = 30;
}
//案例2: 关于特点2
public class Demo2 {
public static void main(String[] args) {
//创建两个对象 ---> test1 test2 是两个独立的对象 每个对象中都有自己的 a b
// Test1 test1 = new Test1();
// Test1 test2 = new Test1();
//
// //对于成员变量来说 成员变量随着对象的创建而存在 对象没有 成员变量也就没有
// System.out.println(test1.a);
// System.out.println(test1.b);
//静态变量 : 是随着 类的加载 而存在 随着类的消失而消失
// 类的加载: 当第一次使用一个类的时候 jvm 会从硬盘中读取字节码文件中的信息 将信息保存到 Java虚拟机的方法区
// 1 类先加载 2 才能创建对象
// 静态变量的存在 先于 对象的存在 ----> 类变量
//直接通过类名访问静态变量
System.out.println(Test1.c);
}
}
class Test1{
// 定义一个成员变量
int a = 10;
int b = 20;
// 定义一个静态变量
static int c = 30;
}
//案例3: 关于特点3
public class Demo2 {
public static void main(String[] args) {
//创建两个对象 ---> test1 test2 是两个独立的对象 每个对象中都有自己的 a b
// Test1 test1 = new Test1();
// Test1 test2 = new Test1();
//
// //对于成员变量来说 成员变量随着对象的创建而存在 对象没有 成员变量也就没有
// System.out.println(test1.a);
// System.out.println(test1.b);
//静态变量 : 是随着 类的加载 而存在 随着类的消失而消失
// 类的加载: 当第一次使用一个类的时候 jvm 会从硬盘中读取字节码文件中的信息 将信息保存到 Java虚拟机的方法区
// 1 类先加载 2 才能创建对象
// 静态变量的存在 先于 对象的存在 ----> 类变量
//直接通过类名访问静态变量
//System.out.println(Test1.c);
//创建对象访问
Test1 test1 = new Test1();// 浪费空间
System.out.println(test1.c);
}
}
class Test1{
// 定义一个成员变量
int a = 10;
int b = 20;
// 定义一个静态变量
static int c = 30;
}
修饰成员方法
概述:
static 修饰成员⽅法: 静态⽅法
语法:
访问修饰符 static 返回值类型 ⽅法名(形参列表){
⽅法的实现;
}
static 访问修饰符 返回值类型 ⽅法名(形参列表){
⽅法的实现;
}
特点:
1.静态的⽅法中 不可以直接访问⾮静态的成员(成员变量 和 成员⽅法)
2.如果要访问⾮静态的成员 必须创建对象 通过引⽤去访问
3.静态⽅法可以通过 类名.⽅法名() 直接访问 也可以通过引⽤去访问(不建议)
4.静态的⽅法可以被继承 静态的⽅法不能被⾮静态的⽅法所覆盖 当子类的静态方法和父类中的静态方法语法上能形成重写的语法但是也不能构成重写,重写注解@Override 不能通过 静态方法的调用不符合多态的特点 (引⽤是什么类型 调⽤的⽅法就是这个类型中的⽅法
5.在静态⽅法中是不可以使⽤ this 和 super 关键字 因为 this 和 super都是和对象有关的⽽静态的成员和对象⽆关 先于对象存在
特点-案例
案例1: 关于特点1
public class Demo2 {
public static void main(String[] args) {
}
}
class Test1 {
// 成员变量
int a = 10;
//静态变量
static int b = 20;
//定义一个成员方法 ---> 可以访问 成员变量 静态变量
public void m1() {
System.out.println(a);
System.out.println(b);
System.out.println("我是成员方法");
}
//定义一个静态方法
public static void m2() {
//System.out.println(a);//访问不了 成员变量 因为成员变量随着对象的创建而存在 静态方法先于 成员变量存在
//m1();
System.out.println(b);
System.out.println("我是静态方法");
}
}
// 问题: 在讲方法的时候,为什么要求 方法的修饰符固定写为 public static ?
// 解答: 就是因为主方法是静态的
//案例2: 关于特点2
public class Demo2 {
public static void main(String[] args) {
}
}
class Test1 {
// 成员变量
int a = 10;
//静态变量
static int b = 20;
//定义一个成员方法 ---> 可以访问 成员变量 静态变量
public void m1() {
System.out.println(a);
System.out.println(b);
System.out.println("我是成员方法");
}
//定义一个静态方法
public static void m2() {
//System.out.println(a);//访问不了 成员变量 因为成员变量随着对象的创建而存在 静态方法先于 成员变量存在
//m1();
//非要访问成员变量 必须创建对象
Test1 test1 = new Test1();
System.out.println(test1.a);
test1.m1();
System.out.println(b);
System.out.println("我是静态方法");
}
}
案例3: 关于特点3
public class Demo2 {
public static void main(String[] args) {
// Test1 test1 = new Test1(); //不建议
//
// test1.m1();//成员方法
// test1.m2();//静态方法
Test1.m2();
}
}
class Test1 {
// 成员变量
int a = 10;
//静态变量
static int b = 20;
//定义一个成员方法 ---> 可以访问 成员变量 静态变量
public void m1() {
System.out.println(a);
System.out.println(b);
System.out.println("我是成员方法");
}
//定义一个静态方法
public static void m2() {
//System.out.println(a);//访问不了 成员变量 因为成员变量随着对象的创建而存在 静态方法先于 成员变量存在
//m1();
//非要访问成员变量 必须创建对象
Test1 test1 = new Test1();
System.out.println(test1.a);
test1.m1();
System.out.println(b);
System.out.println("我是静态方法");
}
}
//案例4: 关于特点4
public class Demo2 {
public static void main(String[] args) {
// TestSub testSub = new TestSub();
// testSub.m2();
// TestSub.m2();// 静态方法可以被继承
// TestSub.m2("刘洋");
//假设 形成的是重写
Test t1 = new TestSub();//父类引用指向子类对象
t1.m2();//引用是什么类型 就会调用 引用中的方法 和对象无关 静态方法没有多态的
}
}
class Test {
//定义一个静态方法
public static void m2() {
System.out.println("我是静态方法");
}
//是否可以重载
public static void m2(int a) {
System.out.println("我是重载的静态方法 m2");
}
}
class TestSub extends Test {
// 是否能够形成子父类之间的方法的重载
public static void m2(String s){
System.out.println("我是子父类之间的方法的重载");
}
// 是否可以被重写
//@Override // 虽然方法的格式 符合 方法的重写 但是本质不是重写
public static void m2(){
System.out.println("我是子类重写后的静态方法m2");
}
}
// 案例5: 关于特点5
public class Demo2 {
public static void main(String[] args) {
// TestSub testSub = new TestSub();
// testSub.m2();
// TestSub.m2();// 静态方法可以被继承
// TestSub.m2("刘洋");
//假设 形成的是重写
Test t1 = new TestSub();//父类引用指向子类对象
t1.m2();//引用是什么类型 就会调用 引用中的方法 和对象无关 静态方法没有多态的
}
}
class Test {
int a = 10;
//定义一个静态方法
public static void m2() {
int a = 20;
System.out.println(a);//20
System.out.println(this.a);
System.out.println("我是静态方法");
}
}
修饰代码块
分类:
(1)局部代码块
(2)动态代码块 ---> 构造代码块
(3)静态代码块
特点:
局部代码块: 定义在方法中
作用:用来限定局部变量的作用域
案例
public class Demo2 {
public static void main(String[] args) {
{
int a = 10;// 7 -- 10
}
{
int a = 20;//14 -- 15
}
}
}
动态代码块(构造代码块 初始代码块): 定义在类中方法外 ---> 成员位置
作用:用于在创建对象时 和成员变量 按照从上向下的顺序进行初始化操作,可以将所有构造方法中共同的代码放到动态代码块中。
案例:
public class Demo2 {
public static void main(String[] args) {
Test test = new Test(30);
}
}
class Test{
int a = 10;// 成员变量
{
System.out.println("我是构造代码块 动态代码块");
System.out.println("有 1000 行初始化代码");
}
public Test(){
System.out.println("我是构造方法");
}
public Test(int a){
//System.out.println("有 1000 行初始化代码 ");
this.a = a;
}
}
静态代码块: 被static修饰的动态代码块
作用:在 类加载时 和静态属性按照顺序进行执行,为类进行初始化操作,一般用于加载驱动等资源。 ----> jdbc
类加载:当jvm第⼀次使⽤⼀个类时 读⼊这个类中的信息(包名 类名 属性 ⽅法 静态的变量 静态的⽅法 。。。)并保存在虚拟机中的过程叫做类加载,
在一个程序运行周期>>内,类加载只进⾏⼀次
类加载时机:
1. 第一次创建对象的时候
2. 第一次通过类名访问类中的静态成员(静态变量 静态方法)时
3. 子类进行类加载首先会先进行父类的类加载
案例:
//案例1: 关于类加载时机 1
public class Demo2 {
public static void main(String[] args) {
//Test t1 ; //声明引用
Test t1 = new Test();// 第一次创建对象
Test t2 = new Test();// 第二次创建对象
}
}
class Test{
static {
System.out.println("我是静态代码块 我的执行可以证明类加载了");
}
public Test(){
System.out.println("构造方法执行了 对象创建完成了");
}
}
//案例2:关于类加载的时机 2
public class Demo2 {
public static void main(String[] args) {
System.out.println(Test.a);
Test.m1();
}
}
class Test {
static int a = 10;
static {
System.out.println("我是静态代码块 我的执行可以证明类加载了");
}
public Test() {
System.out.println("构造方法执行了 对象创建完成了");
}
public static void m1() {
System.out.println("我是静态方法m1");
}
}
// 案例3: 关于类加载时机 3
public class Demo2 {
public static void main(String[] args) {
System.out.println(TestSub.a);
TestSub.m1();
}
}
class Test {
static {
System.out.println("父类的静态代码块执行了 父类的类加载了");
}
}
class TestSub extends Test{
static int a = 10;
static {
System.out.println("子类的静态代码块执行了 子类进行类加载了");
}
public static void m1(){
System.out.println("我是子类的静态方法");
}
}