javaSE——修饰符(含abstract)
1、static修饰符
1、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);
System.out.println(s.age);
//非静态只能用对象访问,尝试用类名访问编译器会报错
System.out.println(s.score);
}
}
静态变量对于类而言在内存中只有一个,能被类的所有实例所共享。
实例变量对于类的每个实例都有一份, 它们之间互不影响.
package com.kuang.oop; public class Student { private static int count;//静态 private int num; public Student() { count++; num++; } public static void main(String[] args) { Student s1 = new Student();//c=1,n=1 Student s2 = new Student();//c=2,n=1 Student s3 = new Student();//c=3,n=1 Student s4 = new Student();//c=4,n=1,c公共,n各自有实例 // 因为还是在类中,所以可以直接访问私有属性 System.out.println(s1.num);//1 System.out.println(s2.num);//1 System.out.println(s3.num);//1 System.out.println(s4.num);//1 System.out.println(Student.count);//count静态,公共的4,下同 System.out.println(s1.count); System.out.println(s2.count); System.out.println(s3.count); System.out.println(s4.count); } }
2、static方法
同理,static修饰的就是静态方法,反之是非静态。
静态方法与非静态的区别
类似,静态方法属于类,“可以也推荐”用类名调用,非静态方法是属于对象的,“”必须“通过对象调用
静态方法不可以直接访问类中的非静态变量和非静态方法,但是可以直接访问类中 的静态变量和静态方法。注:this和super在类中属于非静态变量,因此静态方法不能使用
package com.kuang.oop;
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();
}
思考:为什么静态方法和非静态方法不能直接相互访问? 加载顺序的问题!
静态方法是随着类的加载而加载的,在加载类时,程序就会为静态方法分配内存
非静态方法是属于对象的,对象是在类加载之后创建的
静态方法先于对象存在,因此在对象未存在时非静态的东西也不存在,而静态方法自然不能调用一个当时还不存在的方法。
父类的静态方法可以被子类继承,但是不能被子类重写详见https://www.cnblogs.com/bleu/p/16374463.html继承——4、方法重写
父类的非静态方法不能被子类重写为静态方法 ;
public class Person {
//父类中的非静态方法
public void test() {
System.out.println("Person");
}
}
//编译报错
public class Student extends Person {
//子类中欲重写为静态方法,不允许
public static void test(){
System.out.println("Student");
}
}
3、代码块和静态代码块
【类中可以编写代码块和静态代码块】
public class Person {
{
//代码块(匿名代码块)
}
static{
//静态代码块
}
}
【匿名代码块和静态代码块的执行】
因为没有名字,在程序并不能主动调用这些代码块。
-
匿名代码块是在创建对象的时候自动执行的,并且在构造器执行之前。同时匿名代码块在每次创建对象的时候都会自动执行.
-
静态代码块是在类加载完成之后就自动执行,并且只执行一次.
-
注:每个类在第一次被使用的时候就会被加载,并且一般只会加载一次.
package com.kuang.oop;
public class Person {
{
System.out.println("匿名代码块");
}
static {
System.out.println("静态代码块");
}
public Person() {
System.out.println("构造器");
}
}
public class Student extends Person{
}
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
Student s3 = new Student();
}
}
//结果
//类第一次执行去创建对象s1
静态代码块
匿名代码块
构造器
//s2
匿名代码块
构造器
//s3
匿名代码块
构造器
【匿名代码块和静态代码块的作用】
- 匿名代码块:给成员变量初始化赋值,但是因为构造器也能完成这项工作,所以匿名代码块使用的并不多。
- 静态代码块:给类中的静态成员变量初始化赋值
package com.kuang.oop;
public class Person {
public static String name;
static{
name = "tom";
}
public Person(){
name = "zs";//若没有构造对象,直接通过类名.的方式调用name,则此行不执行
}
}
public class Application {
public static void main(String[] args) {
System.out.println(Person.name);// tom
}
}
注:在构造器中给静态变量赋值,并不能保证能赋值成功,因为构造器是在创建对象的时候才指向,但是静 态变量可以不创建对象而直接使用类名来访问.
4、静态导入包
正常的Math.调用
package com.kuang.oop;
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());
}
}
静态导入包:可以直接输入包内的函数名进行调用,不需要加Math.
package com.kuang.oop;
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);
}
}
静态导入包的好处:这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);就可以将其写入一 个静态方 法print(…),在使用时直接print(…)就可以了。但是这种方法建议在有很多重复调用的时候使用,如果仅 有一到两次调用,不如直接写来的方便。
2、final修饰符
用final修饰的类不能被继承,没有子类。 final之后”断子绝孙”。
java中的String类被定义为final,无法用它创建子类了
【断子绝孙】
public final class Action{
}
//编译报错
public class Go extends Action{
}
用final修饰的方法可以被继承,但是不能被子类的重写。
3、abstract修饰符(抽象类)
abstract修饰符修饰方法就是抽象方法,修饰类就是抽象类
1、抽象类和抽象方法的关系
抽象类中可以包含普通的方法(非抽象方法);
但是有抽象方法的,它所在的类必须声明为抽象类
抽象类其实是对类的一个约束,相似的还有马上就要提到的接口,接口也是一种约束
二者区别:
类——extends——单继承,java里面没有多继承
接口——接口可以实现“多继承”,相当于插排,可以插多个东西
//抽象类
public abstract class Action{
//抽象类让别人去做,有人帮我们实现!
//abstract,抽象方法,只有方法的名字,没有方法的实现
public abstract void doSomething();
}
//继承抽象类的子类(非抽象类的子类),必须实现这个抽象类的方法~
public class A extends Action{
public void doSometing(){
具体实现
}
}
//除非~这个子类也是抽象类,就只能留给孙类了
public abstract class A extends Action{
}
抽象类的特点:
- 不能new这个抽象类,只能靠子类去实现它,是一个约束~
- 抽象类中可以有普通方法
- 抽象方法必须写在抽象类中~
而 接口
是抽象的抽象:约束~
java面试题--抽象类存在构造器吗
存在构造器
即使你没有写任何构造函数,编译器将会为抽象类添加无参数的构造函数,没有的话你的子类将无法编译!!因为在(子)类的任何构造函数中的第一条语句隐式为super()