目录
6.1 关键字static
1 作用
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上
的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,
其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少
对象的情况下,
某些特定的数据在内存空间里只有一份,
例如所有的中国人都有个
国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中
都单独分配一个用于代表国家名称的变量。
static修饰的变量或方法不属于某一个类所有。
2 static关键字使用
static:静态的
static可以用来修饰:属性、方法、代码块、内部类
3 使用static修饰属性
静态变量、类变量
属性分为
静态属性(static) 和
非静态属性(实例变量)
实例变量:我们创建了多个类的对象,每个对象都独立拥有一套类中的非静态属性。当修改一个对象的非静态属性时,不会导致其他对象非静态属性值修改。
静态变量:我们创建了多个类的对象,共享一个静态变量。当修改一个对象的静态变量时,其他对象调用此变量,是修改过的。
其他说明:
-
静态变量随着类的加载而加载(实例变量随着对象的创建而创建),静态变量加载早于对象创建。
-
由于类只加载一次,静态变量在内存中只存在一份, 存在 方法区 的 静态域 中。
-
类变量 实例变量
类 yes no
对象 yes yes
静态属性举例:
System.out :out为System类的静态属性
class Chinese{
String name;
static String nation;
}
//测试
Chinese c1 = new Chinese();
c1.name = '张三';
c2.nation = 'CHN';
Chinese c2 = new Chinese();
c2.name = '李四';
sysout(c2.nation); //此时c2的nation有值,为'CHN'
4 使用static修饰方法
-
使用与属性相似。
-
静态方法中,只能调用静态的方法和属性;非静态方法中,可以调用静态的方法和属性。
-
静态方法中不能使用this和super关键字。(生命周期不够,关于静态属性和方法的使用,大都从生命周期角度解释)
开发中,如何确定一个属性是否声明为static的?
-
属性可以被多个对象共享,不会随着对象的不同而不同。
-
类中的常量也常常被修饰为static。
开发中,如何确定一个方法是否声明为static的?
-
操作静态属性的方法通常设置为静态。
-
工具类中的方法,习惯声明为static。如:Math、Arrays、Collections。
举例:
class Circle{
private double r;//圆的半径
private static int total; //记录第几个对象(多个对象共有的,需要声明为静态的)
public Circle() {
total++;
}
public Circle(){
this();
this.r = r;
}
public static int getTotal() { //注意方法为静态的
return total;
}
public static void setTotal(int total) {
Circle.total = total;
}
}
应用:单例设计模式
1 概念
设计模式:设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、
以及解决问题的思考方式。
单例设计模式:就是采取一定的方法保证在整个的软件系统中,
对
某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构
造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生
类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无
法得到类的对象,
只能调用该类的某个静态方法以返回类内部创建的对象
,
静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象
的变量也必须定义成静态的。
2 实现
1. 饿汉式:
2. 懒汉式:懒汉式暂时还存在线
程安全问题,讲到多
线程时,可修复
3 区分懒汉式与饿汉式
饿汉式:
好处:是线程安全的。
坏处:对象加载时间过长。
懒汉式:
好处:延迟对象的创建。
坏处:目前的写法是线程不安全的。(线程1在进行到判断与new之前时,线程二判断对象还是null,会创造两个对象)
4 单例设计模式优点
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的
产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可
以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方
式来解决。
5 应用
-
网站的计数器,一般也是单例模式实现,否则难以同步。
-
应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志 文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
-
数 据库 连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库 资源。
-
项目中, 读取配置文件的类,一般也只有一个对象。没有必要每次使用配置 文件数据,都生成一个对象去读取。
-
Application 也是单例的典型应用
-
Windows的Task Manager ( 任务管理器)就是很典型的单例模式
-
Windows的Recycle Bin ( 回收站)也是典型的单例应用。在整个系统运行过程 中,回收站一直维护着仅有的一个实例。
6.2 理解main方法语法
1 使用说明
-
main()作为程序入口。
-
main()也是一个普通的静态方法。
-
main()可以作为我们与控制台交互的方式。(之前:使用Scanner)
public class Test {
public static void main(String[] args) {
for(int i = 0; i < args.length; i++) {
System.out.println("***"+args[i]);
}
}
}
在eclipse中交互:右键 -> run as -> java application(先编译) -> Run As ->run configurations -> 找到编译过的文件 ->arguments中输入参数
控制台交互:java name data1 data2 data3 ...
6.3 类的成员之四:代码块
1 作用
初始化类或对象。
2 修饰
如果有修饰的话,只能使用static修饰。可以分成
静态代码块和
非静态代码块。
继承情况下的执行顺序:(由父及子,静态先行)
父类的静态代码块 ->
子类的静态代码块 ->
父类的非静态代码块 ->
父类的构造器 ->
子类的非静态代码块 ->
子类的构造器
属性赋值的顺序:
默认初始化 -> 显式初始化/代码块赋值(取决于谁先写) -> 构造器初始化-> 有对象以后调用对象.属性或对象.方法赋值。
6.4 final关键字
1 修饰的结构:类、方法、变量
2 修饰类
final修饰的类不能被继承。String, System, StringBuffer
3 修饰方法
final修饰的方法不能被重写。Object中的getClass();
4 修饰变量
final修饰为常量。
final修饰属性:可以考虑采用显式初始化、代码块初始化、构造器初始化(定义多个构造器,则每个构造器都需要赋值一次)
简单的赋值,并且所有对象值相同,可采用显式初始化;复杂的赋值需要代码块;每个对象值各不相同可以使用构造器初始化。
final修饰局部变量:尤其是修饰形参时,调用此方法时赋值,赋值以后只能使用不能修改。
static final:修饰属性:全局常量
修饰方法:一般不常用
举例:
public class Something {
public static void main(String[] args) {
Other o = new Other();
new Something().addOne(o);
}
public void addOne(final Other o) {
// o = new Other(); //报错
o.i++; //不会报错,o不可以修改,但是o中的属性可以修改
}
}
class Other {
public int i;
}
6.5 抽象类与抽象方法
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一
般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父
类设计得非常抽象,以至于它没有具体的实例,这样的类叫做
抽象类
。
1 abstract关键字使用
abstract:抽象的
可以用来修饰的结构:类、方法
2 修饰类:抽象类
abstract class Person{
}
-
此类不能实例化。
-
类中仍然提供构造器,便于子类对象实例化时调用。
-
开发中,都会提供子类,让子类对象实例化。
3 修饰方法
public abstract void method();
-
只有方法的声明,没有方法体。
-
包含抽象方法的类,一定是抽象类。反之,抽象类中可以没有抽象方法。
-
若子类重写了父类中的抽象方法之后,子类方可实例化。否则,子类为抽象类,需要用abstract修饰。
4 应用
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提
供具体实现的对象的类。
5 注意点
-
abstract不能用来修饰:属性、构造器等结构。
-
不能用来修饰私有方法、静态方法、final方法、final类。
6 抽象类的匿名子类
public class Test {
public static void main(String[] args) {
Worker worker = new Worker();
method(worker);//非匿名类非匿名对象
method(new Worker());//非匿名类匿名对象
//创建了匿名子类对象p,(省事,不用特意在造一个子类)
Person p = new Person() {
@Override
public void eat() {
}
};
}
public static void method(Person p) {
p.eat();
}
}
abstract class Person{
public abstract void eat();
}
class Worker extends Person{
public void eat() {
}
}
多态的应用:模板方法设计模式
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模
板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象
类的行为方式。
解决的问题:
-
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以 把不确定的部分暴露出去,让子类去实现。
-
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用, 这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽 象出来,供不同子类实现。这就是一种模板模式。
举例:
public class Test {
public static void main(String[] args) {
SubTemplate t = new SubTemplate();
t.spendTime();
}
}
abstract class Template{
//计算某段代码计算花费时间
public void spendTime() {
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
public abstract void code();
}
class SubTemplate extends Template{
public void code() {
//要测试的代码体
}
}
6.6 接口
1 作用
-
有时必须从几个类中派生出一个子类,继承它们所有的属性和方 法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
-
有时必须从几个类中抽取出一些共同的行为特征,而它们之间又 没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打 印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都 支持USB连接。
2 使用
-
使用interface定义。
-
java中,接口和类是并列的两个结构
3 如何定义接口:接口中的成员
jdk7及以前:只能定义全局常量(public static final) 和抽象方法(public abstract)
interface Flyable{
public static final int MAX_SPEED = 7900; //public static final可以省略掉,默认为静态常量
public abstract void fly(); //public abstract可以省略掉
}
注:
-
接口不能定义构造器,意味着接口不能实例化。
-
接口同通过让类实现的方式使用。如果实现类覆盖了接口左右抽象方法,就可以实例化。