5.1static关键字
1.当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
2.1)class Circle {
private double radius;
public Circle(double radius){this.radius=radius;}
public double findArea(){return Math.PI*radius*radius;}
}
2)创建两个Circle对象
Circle c1=new Circle(2.0); //c1.radius=2.0
Circle c2=new Circle(3.0); //c2.radius=3.0
3)Circle类中的变量redis是一个实例变量(instance variable),它属于类的每一个对象,不能被同一个类的不同对象所共享。
4)上例中c1的radius独立于c2的radius,存储在不同的空间。c1中的radius变化不会影响c2的radius,反之亦然。
如果想让一个类的所有实例共享数据,请用类变量。
3.1)在Java类中声明变量、方法和内部类时,可使用关键字static作为修饰符。
2)static标记的变量或方法由整个类(所有实例)共享,如访问控制权限允许,可不必创建该类对象而直接用类名加‘ . ’调用。
3)static成员也称类成员或静态成员,如:类变量、类方法、静态方法等。
4.类变量(类属性)由该类的所有实例共享
5.类属性(class Method)应用举例
public class Person3 {
private int id;
public static int total=0;
public Person3(){
total++;
id=total;
}
public static void main(String[] args) {
Person3 tom=new Person3();
tom.id=0;
total=100; // 不用创建对象就可以访问静态成员
}
}
public class OtherClass {
public static void main(String[] args) {
Person3.total=100;// 不用创建对象就可以访问静态成员
//访问方式:类名.类属性类名.类方法
System.out.println(Person3.total);
Person3 c = new Person3();
System.out.println(c.total); //输出101
}
}
6.类方法(class Method)
1)没有对象的实例时,可以用类名.方法名()的形式访问由static标记的类方法。
public class Person4 {
private int id;
private static int total = 0;
public static int getTotalPerson() {
return total;
}
public Person4() {
total++;
id = total;
}
}
public class TestPerson4 {
public static void main(String[] args) {
System.out.println("Number of total is " +Person4.getTotalPerson());
//没有创建对象也可以访问静态方法
Person4 p1 = new Person4();
System.out.println( "Number of total is "+ Person4.getTotalPerson());
} //输出:Number of total is 0
} Number of total is 1
2)在static方法内部只能访问类的static属性,不能访问类的非static属性。
class Person {
private int id;
private static int total = 0;
public static int getTotalPerson() {
id++; //非法
return total;
}
public Person() {
total++;
id = total;
}
}
3)因为不需要实例就可以访问static方法,因此static方法内部不能有this,(也不能有super?)
class Person {
private int id;
private static int total = 0;
public static void setTotalPerson(int total){
this.total=total; //非法,在static方法中不能有this,也不能有super
}
public Person() {
total++;
id = total;
}
}
public class TestPerson {
public static void main(String[] args) {
Person.setTotalPerson();
}
}
4)在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。
5)静态方法不能以任何方式引用this和super关键字。与上面的道理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生。
6)main()方法是静态的,因此JVM在执行main方法时不创建main方法所在的类的实例对象,因而在main()方法中,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在以后的例子中会多次碰到。
7.类属性、类方法的设计思想
1)类属性作为该类各个对象之间共享的变量。在设计类时,分析哪些类属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
2)如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建创建对象就可以调用类方法,从而简化了方法的调用。
8.静态初始化
1)一个类中可以使用不包含在任何方法体中的静态代码块(static blook),当类被载入时,静态代码块被执行,且只被执行一次,静态块经常用来进行类属性的初始化。
2)static块通常用于初始化static(类)属性
3)class Person {
public static int total;
static {
total = 100;//为total赋初值
}
…… //其它属性或方法声明
}
4)静态初始化
public class Person1 {
public static int total;
static{
total=100;
System.out.println("in static block");
}
}
public class Test1 {
public static void main(String[] args) {
System.out.println("total = "+ Person1.total);
System.out.println("total = "+ Person1.total);
}
}
8.单例Singleton设计模板
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免得我们自己再去思考和摸索。
所谓类的单态设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
举例:
public class Single {
private static Single onlyone=new Single();//私有的,只能在类的内部访问
private String name;
public static Single getSingle() {//getSingle()为static,不用创建对象 即可访问
return onlyone;
}
private Single(){}//private的构造器,不能在类的外部创建该类的对象
}
public class TestSingle {
public static void main(String[] args) {
Single s1 = Single.getSingle(); //访问静态方法
Single s2 = Single.getSingle();
if (s1==s2){
System.out.println("s1 is equals to s2!");
}
}
}
9.理解main方法的语法
由于java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。
10.关键字final
1)在Java中声明类、属性和方法时,可使用关键字final来修饰。
2)final标记的变量()
5.2final关键字
1.在Java中声明类、属性和方法时,可使用关键字final来修饰
2.final标记的变量(成员变量或局部变量)即成为常量,只能赋值一次
3.final标记的类不能被继承。提高安全性,提高程序的可读性。
4.final标记的方法不能被子类重写。增加安全性。
5.final标记的成员变量必须在声明的同时或在每个构造方法中显式赋值,然后才能使用。
6.关键字final应用举例:
public final class Test2 {
public static int totalNumber=5;
public final int id;
public Test2(){
id=++totalNumber;//只能在构造方法中给final变量赋值
}
public static void main(String[] args) {
Test2 t=new Test2();
System.out.println(t.id);
final int i=10;
final int j;
j=20;
// j=30; //非法
}
}
5.3抽象类(abstract关键字)
1.随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
2.用abstract关键字来修饰一个类时。这个类叫做抽象类;用abstract来修饰一个方法时,该方法叫做抽象方法。
3.抽象方法:只有方法的声明,没有方法的实现。以分号结束。
abstract int abstractMethod1(int a);
4.含有抽象方法的类必须被声明为抽象类。
5.抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。
6.不能用abstract修饰私有方法,构造方法,静态方法。
7.抽象类举例:
public abstract class A {
abstract void m1();
public void m2(){
System.out.println("A类中定义的m2方法");
}
}
public class B extends A{
void m1(){
System.out.println("B类中定义的m1方法");
}
}
public class Test3 {
public static void main( String args[ ] ){
A c = new B( );
c.m1( );
c.m2( );
}
}
8.抽象类应用
1)抽象类是用来模型化那些父类 无法确定全部实现,而是由其子类提供具体实现的对象的类。
2.在航运公司系统中,Vehicle类需要定义两个方法分别计算运输工具的燃料效率和行驶距离。
问题:卡车(Truck)和驳船(RiverBarge)的燃料效率和行驶距离的计算方法完全不同。Vehicle类不能提供计算方法,但子类可以。
解决方案 Java允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。
Vehicle是一个抽象类,有两个抽象方法。
public abstract class Vehicle{
public abstract double calcFuelEfficiency(); //计算燃料效率的抽象方法 public abstract double calcTripDistance(); //计算行驶距离的抽象方法 } public class Truck extends Vehicle{ public double calcFuelEfficiency( ) { //写出计算卡车的燃料效率的具体方法 } public double calcTripDistance( ) { //写出计算卡车行驶距离的具体方法 } } public class RiverBarge extends Vehicle{ public double calcFuelEfficiency( ) { //写出计算驳船的燃料效率的具体方法 } public double calcTripDistance( ) { //写出计算驳船行驶距离的具体方法} }
注意:抽象类不能实例化 new Vihicle()是非法的
5.4接口(interface关键字)
1.有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
2.接口(interface)是抽象方法和常量值的定义的集合。
3.从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
4.接口定义举例
public interface Runner {
int id = 1;
public void start();
public void run();
public void stop();
}
5.接口的特点:
- 用interface来定义
- 接口中的所有成员变量都默认是由public static final 修饰的。
- 接口中的所有方法都默认是由public abstract修饰的。接口没有构造方法。
- 实现接口的类中必须提供接口中所有方法的具体实现内容。
- 多个无关的类可以实现同一个接口。
- 一个类可以实现多个无关的接口。
- 与继承关系类似,接口与实现类之间存在多态性。
- 接口也可以继承另一个接口,使用extends关键字。
6.实现接口的类中必须提供接口中所有方法的具体实现内容。
多个无关的类可以实现同一个接口。
一个类可以实现多个无关的接口。
与继承关系类似,接口与实现类之间存在多态性。
7.定义Java类的语法格式:
< modifier> class < name> [extends < superclass>]
[implements < interface> [,< interface>]* ] {
< declarations>*
}
8.接口应用举例:
例1:
public interface Runner {
public void start();
public void run();
public void stop();
}
public class Person implements Runner{
public void start() {
// 准备工作:弯腰、蹬腿、咬牙、瞪眼 // 开跑
}
public void run() {
// 摆动手臂
// 维持直线方向
}
public void stop() {
// 减速直至停止、喝水。
}
}
例2:
例3:一个类可以实现多个无关的接口
interface Runner { public void run();} interface Swimmer {public double swim();} class Animal {public int eat(){…}} class Person extends Animal implements Runner,Swimmer{ public void run() {……} public double swim() {……} public int eat() {……} }
与继承关系类似,接口与实现类之间存在多态性
public class Test{ public static void main(String args[]){ Test t = new Test(); Person p = new Person(); t.m1(p); t.m2(p); t.m3(p); } public String m1(Runner f) { f.run(); } public void m2(Swimmer s) {s.swim();} public void m3(Animal a) {a.eat();} }
9.接口的其它问题
如果实现接口的类中没有实现接口中的全部方法,必须将此类定义为抽象类。
接口也可以继承另一个接口,使用extends关键字。
public interface MyInterface {
String s="interface";
public void absM1();
}
public interface SubInterface extends MyInterface{
public void absM2();
}
public class SubAdapter implements SubInterface{
public void absM1(){System.out.println("absM1");}
public void absM2(){System.out.println("absM2");}
}
实现类SubAdapter必须给出接口SubInterface以及父接口MyInterface中所有方法的实现。
5.5内部类
1.
- 在Java中,允许一个类的定位位于另一个类的内部,前者称为内部类
- 内部类和外层封装它的类之间存在逻辑上的所属关系。
- Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。Inner class的名字不能与包含它的类名相同。
- Inner class可以使用包含它的类的静态和实例成员变量,也可以使用它所在方法的局部变量。
2.内部类举例1:
public class A2 {
private int s;
public class B{
public void mb(){
s=100;
System.out.println("在内部类B中s=" + s);
}
}
public void ma() {
B i = new B();
i.mb();
}
}
public class TestA2 {
public static void main(String[] args) {
A2 o=new A2();
o.ma();
}
}
3.内部类举例2:
public class A3 {
private int s=111;
public class B{
private int s=222;
public void mb(int s){
System.out.println("局部变量"+s); // 局部变量s
System.out.println("内部类对象的属性"+this.s);// 内部类对象的属性s
System.out.println("外层类对象属性"+A3.this.s);// 外层类对象属性s
}
}
public static void main(String[] args) {
A3 a = new A3();
A3.B b = a.new B();
b.mb(333);
}
}
4.内部类特性
1)Inner class可以声明为抽象类,因此可以被其它的内部类继承。也可以声明为final的。
2)和外层类不同,Inner class可以声明为private或protected。
3)Inner class可以声明为static的,但此时就不能再使用外层封装类的非static的成员变量。
4)非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员。