关键字static
使用场景
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,这个时候就可以使用我们的static。
使用范围:
Java类中,可用static修饰属性、方法、代码块、内部类
特点:
随着类的加载而加载
优先于对象存在
修饰的成员,被所有对象所共享
访问权限允许时,可不创建对象,直接被类调用
类变量
类变量(类属性)由该类的所有势力共享
类方法
没有对象的实例时,可以用类名.方法名()的形式访问由static标记的类方法。
在static方法内部只能访问类的static属性,不能访问类的非static属性
因为不需要实例就可以访问static方法,因此static方法内部不能有this也不能有super
重载的方法需要同时为static的或者非static的
单例(singleton)设计模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索。
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
如果我们要让类在一个虚拟机中只能产生一个对象,
我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。
因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
下面说人话:禁止外部通过New创建对象
在其内部创建对象,之后外部使用其在内部new的对象
保证整个虚拟机(应用)中仅有一个对象产生,以满足业务需求
实例化对象的创建要消耗大量的时间和资源,频繁new对象没有意义。
单例设计模式之一:饿汉式构造方法私有化。无法再通过new来创建该类的对象。
创建一个该类型的私有类变量。
通过一个public静态方法访问这个私有类变量。
class Example {
private Example() {} //重写构造方法
private static Example e = new Example(); //创建唯一实例作为私有类变量
public static Example getInstance() {
return e;
} //为类外访问该唯一实例提供public方法
}
单例设计模式之二:懒汉式
它与饿汉模式的区别是,它一开始没有new对象(null),直到第一次调用才new出一个对象,而之后所有调用都是调用这个唯一的对象。
这两种单例模式的根本区别在于:对象何时创建。
懒汉式的步骤为:构造方法私有化。
创建该类型的一个私有变量,但赋值为null。
创建一个public静态方法访问这个私有变量。如果当前为null,则new一个;如果当前不是null,则直接返回已有的私有变量。
class Example {
private Example() {}
private static Example e = null;
public static Example getInstance() {
if (e == null) {
e = new Example();
}
return e;
}
}
main方法的语法
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
JVM需要调用类的main方法,所以该方法必须是public。
执行main方法时不需要创建对象,它是一个类方法,所以为static。
main方法接受一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。
编译后,若执行如下命令:
java TestMain.java aa bb cc //aa bb cc为调用main方法时传入的参数
控制台输出一下内容
aa
bb
cc
初始化块(代码块)
执行顺序为:类的属性的默认初始化和显示初始化。
执行代码块的代码。
如果有多个代码块,则顺序执行
执行构造器的代码。
静态代码块
静态代码块中只能对静态属性和静态方法进行初始化。
无论new多少个对象,静态代码块只执行一次
class Test02 {
static String name;
public Test02() {
System.out.println("构造方法赋值");
name="test02";
System.out.println(name);
}
static
{
System.out.println("代码块赋值");
name="test01";
System.out.println(name);
}
public static void main(String[] args) {
Test02 t = new Test02();
Test02 t1 = new Test02();
}
}
以下为输出结果
代码块赋值 // t
test01
构造方法赋值 // t
test02
构造方法赋值 //t1
test02
对比
非静态代码块:没有static修饰的代码块可以有输出语句。
可以对类的属性进行初始化操作。
可以调用静态或非静态的变量或方法。
若有多个非静态的代码块,按照从上到下的顺序依次执行。
每次创建对象的时候,都会执行一次。
优先于构造器执行。
静态代码块:用static修饰的代码块不可以对非静态的属性初始化,即不可以调用非静态的属性和方法。
若有多个静态代码块,则按顺序执行。
静态代码块优先于非静态代码块执行。
静态代码块只执行一次。
final关键字
使用final修饰类、属性和方法,表示“最终”。final修饰的类不能被继承。例如String类、System类、StringBuffer类。
final修饰的方法不能被子类重写。例如Object类中的getClass()。
final修饰的变量(成员变量或局部变量)则为常量,注意一般将其名称大写,如有多个单词则用下划线连接。常量必须显式赋值且只能赋值一次。
final static一起修饰的变量就叫做全局常量。
抽象类
abstract关键字:用abstract修饰的类叫做抽象类。
用abstract修饰的方法叫做抽象方法。抽象方法只包含方法的声明,不包含方法的实现,以分号结束。
abstract int abstractMethod(int a);
含有抽象方法的类必须被声明为抽象类。
抽象类不能被实例化。抽象类是用来作为父类被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,则仍为抽象类。
不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法。
接口(interface)有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是Java不支持多重继承。利用接口可以实现多重继承的效果。
接口是抽象方法和常量值的定义的集合。
从本质上讲,接口是一种特殊的抽象类,这种抽象类只包含常量和方法的定义,而没有变量和方法的实现。
接口类的实现:class SubClass implements intergaceA{ }
一个类可以实现多个接口,接口也可以继承其他接口。
接口的特点:用interface来定义;
接口中的所有成员变量都默认是由public static final修饰的,即全局静态常量;
接口中的所有方法都默认是由public abstract修饰的;
接口没有构造器,不能new;
接口采用多层继承机制;
实现接口的类必须提供接口中所有方法的具体实现内容(大括号),方可实例化。否则仍为抽象类,要在类前加abstract才不会报错;
接口的主要用途就是被实现类实现;
与继承关系类似,接口与实现类之间存在多态性;
语法格式:先extends(继承父类),后写implements(实现接口)。
抽象类与接口类的区别:抽象类可以有默认的方法实现,接口不存在方法的实现
抽象类使用 extends 来实现继承,且子类必须提供抽象类中的方法实现,否则子类也是抽象类;接口使用 implements 来实现接口,也需要声明的方法实现
抽象类可以有构造器,而接口不能有构造器
抽象类一般表示的是一种继承关系,一个子类只能继承一个父类,但是可以实现多个接口
抽象方法可以有 public,protected,default 这些修饰符,接口默认修饰符为 public
内部类
若一个类位于另一个类的内部,则前者为内部类,后者为外部类。
Inner class 可以使用外部类的私有数据。若外部类要访问内部类中的成员需要以如下形式:内部类.成员 或 内部类对象.成员。
内部类的特点:可以是final的;
可以是private和protected的;
可以为static的,但此时不能再使用外部类的非 static 成员变量;
可以声明为abstract的,因此可以被其他的内部类继承;
非static的内部类中的成员不能声明为static的,只有在外部类或static的内部类中才可声明static成员。
比如说想在A类中同时重写B的一个方法和C的一个方法。则:
public class Test {
public static void main(String[] args) {
A a = new A();
a.testB();
a.testC();
}
}