接java日常记录5
上一讲我们讲了面向对象的三大特性,这一次我们在三大特性的基础之上,记录static修饰符的使用:
在类中,使用static修饰的成员变量就是静态变量,反之为非静态变量。
静态变量和非静态变量的区别
静态变量属于类的,”可以”使用类名来访问,非静态变量是属于对象的,”必须”使用对象来访问.
public class Student{
private static int age;
private double score;
public static void main(String[] args) {
Student s = new Student();
//推荐使用类名访问静态成员
System.out.println(Student.age);//static修饰的变量,可以通过ClassName.静态变量名
//也可以通过实例化对象的别名来访问实例化对象.静态变量
//没有被static修饰的只能通过实例化对象调用
System.out.println(s.age);
System.out.println(s.score);
}
}
静态变量对于类而言在内存中只有一个,能被类的所有实例所共享。实例变量对于类的每个实例都有一份, 它们之间互不影响.
public class Student{
private static int count;
private int num;
public Student() {
count++;
num++;
}
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
Student s3 = new Student();
Student s4 = new Student();
//因为还是在类中,所以可以直接访问私有属性
System.out.println(s1.num);
System.out.println(s2.num);
System.out.println(s3.num);
System.out.println(s4.num);
System.out.println(Student.count);
System.out.println(s1.count);
System.out.println(s2.count);
System.out.println(s3.count);
System.out.println(s4.count);
}
}
在加载类的过程中为静态变量分配内存,实例变量在创建对象时分配内存,所以静态变量可以使用类名来 直接访问,而不需要使用对象来访问.
静态方法”不可以”直接访问类中的非静态变量和非静态方法,但是”可以”直接访问类中的静态变量和静态方法
注意:this和super在类中属于非静态的变量.(静态方法中不能使用)
public class Student{
private static int count;
private int num;
public void run(){}
public static void go(){}
public static void test(){
//编译通过
System.out.println(count);
go();
//编译报错
System.out.println(num);
run();
}
}
非静态方法”可以”直接访问类中的非静态变量和非静态方法,也”可以”直接访问类中的静态变量和静态方法
public class Student{
private static int count;
private int num;
public void run(){} //static修饰符不见
public static void go(){}
public void test(){//static修饰符去除
//编译通过
System.out.println(count);
go();
//编译通过
System.out.println(num);
run();
}
}
为什么静态方法和非静态方法不能直接相互访问?
加载顺序的问题!
父类的静态方法可以被子类继承,但是不能被子类重写
public class Person {
public static void method() {}
}
//编译报错
public class Student extends Person {
// 父类的静态方法可以被子类继承,但是不能被子类重写
public void method(){}
}
//例如:
public class Person {
public static void test() {
System.out.println("Person");
}
}
//编译通过,但不是重写
public class Student extends Person {
public static void test(){
System.out.println("Student");
}
}
public static void main(String[] args) {
Perosn p = new Student();
p.test();//输出Person
p = new Person();
p.test();//输出Perosn
}
}
//和非静态方法重写后的效果不一样
父类的非静态方法不能被子类重写为静态方法
public class Person {
public void test() {
System.out.println("Person");
}
}
//编译报错
public class Student extends Person {
public static void test(){
System.out.println("Student");
}
}
代码块和静态代码块
public class Person {
{
//代码块(匿名代码块)
}
static{
//静态代码块
}
}
【匿名代码块和静态代码块的执行】
因为没有名字,在程序并不能主动调用这些代码块。 匿名代码块是在创建对象的时候自动执行的,并且在构造器执行之前。同时匿名代码块在每次创建对象的时候都会自动执行. 静态代码块是在类加载完成之后就自动执行,并且只执行一次.
注:每个类在第一次被使用的时候就会被加载,并且一般只会加载一次.
package staticInfo;
import static java.lang.Math.random; //这个叫静态导入包
/**
* 关于static的注意事项
* @author Administrator
*
*/
public class Demo01{
private static String name = "ss";; //静态的变量 多线程
private String sc = "cc"; //非静态的方法
public void run(){
System.out.println(random());//由于是静态导入包,从而不需要Math.random()
}
public static void go(){
}
{
//第二个执行 主要是为了赋值赋初始值
System.out.println("匿名代码块");
//代码块()匿名代码块
}
static{
//第一个执行
System.out.println("静态代码块");
//静态代码块 (注意在类加载直接执行,且永久只执行一次)
}
//第三个执行
public Demo01() {
System.out.println("无参构造方法");
}
public static void main(String[] args) {
Demo01 d1 = new Demo01();
System.out.println(Demo01.name);
// System.out.println(Demo01.sc);
System.out.println(d1.sc);
System.out.println(d1.name);
d1.run();
//d1.go(); //你会发现通过实例化调用方法是可以的
Demo01.go();//但是通过类类调用反方法是不行的
go();//静态的方法可以直接调用
Demo01 d2 = new Demo01();
}
}
结果为:
静态代码块
匿名代码块
无参构造方法
ss
cc
ss
0.6253055102509081
匿名代码块
无参构造方法
【匿名代码块和静态代码块的作用】
匿名代码块的作用是给对象的成员变量初始化赋值,但是因为构造器也能完成这项工作,所以匿名代码块 使用的并不多。
public class Person {
public static String name;
static{
name = "tom";
}
public Person(){
name = "zs";
}
public static void main(String[] args) {
System.out.println(Person.name);//tom
}
}
注:在构造器中给静态变量赋值,并不能保证能赋值成功,因为构造器是在创建对象的时候才指向,但是静态变量可以不创建对象而直接使用类名来访问.
创建和初始化对象的过程
Student s = new Student();
【Student类之前没有进行类加载】
1.类加载,同时初始化类中静态的属性
2.执行静态代码块
3.分配内存空间,同时初始化非静态的属性(赋默认值,0/false/null)
4.调用Student的父类构造器
5.对Student中的属性进行显示赋值(如果有的话)
6.执行匿名代码块
7.执行构造器
8.返回内存地址
注:子类中非静态属性的显示赋值是在父类构造器执行完之后和子类中的匿名代码块执行之前的时候
public class Person{
private String name = "zs";
public Person() {
System.out.println("Person构造器");
print();
}
public void print(){
System.out.println("Person print方法: name = "+name);
}
public static void main(String[] args) {
new Student();
}
}
class Student extends Person{
private String name = "tom";
{
System.out.println("Student匿名代码块");
}
static{
System.out.println("Student静态代码块");
}
public Student(){
System.out.println("Student构造器");
}
public void print(){
System.out.println("student print方法: name = "+name);
}
}
结果:
Student静态代码块
Person构造器
student print方法: name = null
Student匿名代码块
Student构造器
静态导入
静态导包就是java包的静态导入,用import static代替import静态导入包是JDK1.5中的新特性。意思是导入这个类里的静态方法。
好处:这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);就可以将其写入一 个静态方法print(…),在使用时直接print(…)就可以了。但是这种方法建议在有很多重复调用的时候使用,如果仅
有一到两次调用,不如直接写来的方便。
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
//之前是需要Math.random()调用的
System.out.println(random());
System.out.println(PI);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/198025.html