为描述和处理个人信息,定义类Person:
public class Person { public String name; public int age; public String getInfo() {...} }
Student类继承了父类Person的所有属性和方法,并增加了一个属性school。Person中的属性和方法,Student都可以利用。
作用:
继承的出现提高了代码的复用性。继承的出现让类与类之间产生了关系,提供了多态的前提。不要仅为了获取其他类中某个功能而去继承,继承要有逻辑关系在里面,不要随意继承。一个变量只能有一种确定的数据类型
一个引用类型变量可能指向(引用)多种不同类型的对象
Person p = new Person(); Person e = new Student(); // Person类型的变量e,指向Student类型的对象子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。
一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
Student m = new Student(); m.school = “pku”; //合法,Student类有school成员变量 Person e = new Student(); e.school = “pku”; //非法,Person类没有school成员变量属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。
正常的方法调用
Person p = new Person(); p.getInfo(); Student s = new Student(); s.getInfo();虚拟方法调用(多态情况下)
Person e = new Student(); e.getInfo(); //调用Student类的getInfo()方法编译时类型和运行时类型 编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。——动态绑定
方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法
public class Test{ public void method(Person e) { //…… e.getInfo(); } public static void main(Stirng args[]){ Test t = new Test(); Student m = new Student(); t.method(m); //子类的对象m传送给父类类型的参数e } }要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
如果x属于类A的子类B,x instanceof A值也为true。
public class Person extends Object {…} public class Student extends Person {…} public class Graduate extends Person {…} ------------------------------------------------------------------- public void method1(Person e) { if (e instanceof Person) // 处理Person类及其子类对象 if (e instanceof Student) //处理Student类及其子类对象 if (e instanceof Graduate) //处理Graduate类及其子类对象 }Object类是所有Java类的根父类
如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类
public class Person { ... }等价于:
public class Person extends Object { ... }例:
method(Object obj){…}//可以接收任何类作为其参数 Person o=new Person(); method(o);基本类型比较值:只要两个变量的值相等,即为true.
int a=5; if(a==6){…}引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,==才返回true.
Person p1=new Person(); Person p2=new Person(); if (p1==p2){…}用“==”进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错; 对于对象来说: 特殊的类,比如String.File.Date,使用= =比较的是对象(对象的地址),equals比较的是内容 除了特殊的类之外的其他普通的类的对象,= =和equals比较的都是对象(对象的内存地址) 如果想改变某一个类equals,不想用equals比较对象的内存地址,需要重写equals方法
toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。
在进行String与其它类型数据的连接操作时,自动调用toString()方法
Date now=new Date(); System.out.println(“now=”+now); 相当于 System.out.println(“now=”+now.toString());可以根据需要在用户自定义类型中重写toString()方法 如String 类重写了toString()方法,返回字符串的值。
s1=“hello”; System.out.println(s1);//相当于System.out.println(s1.toString());基本类型数据转换为String类型时,调用了对应包装类的toString()方法
int a=10; System.out.println(“a=”+a);通过包装类的构造器实现:
int i = 500; Integer t = new Integer(i);还可以通过字符串参数构造包装类对象:
Float f = new Float(“4.56”); Long l = new Long(“asdf”); //NumberFormatException获得包装类对象中包装的基本类型变量 —拆箱 调用包装类的.xxxValue()方法:
boolean b = bObj.booleanValue();JDK1.5之后,支持自动装箱,自动拆箱。但类型必须匹配。
字符串转换成基本数据类型 通过包装类的构造器实现:
int i = new Integer(“12”);通过包装类的parseXxx(String s)静态方法:
Float f = Float.parseFloat(“12.1”);基本数据类型转换成字符串 调用字符串重载的valueOf()方法:
String fstr = String.valueOf(2.34f);更直接的方式:
String intStr = 5 + “”当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
class Circle{ private double radius; public Circle(double radius){this.radius=radius;} public double findArea(){return Math.PI*radius*radius;} }创建两个Circle对象
Circle c1=new Circle(2.0); //c1.radius=2.0 Circle c2=new Circle(3.0); //c2.radius=3.0Circle类中的变量radius是一个实例变量(instance variable),它属于类的每一个对象,不能被同一个类的不同对象所共享。 上例中c1的radius独立于c2的radius,存储在不同的空间。c1中的radius变化不会影响c2的radius,反之亦然。
① 没有对象的实例时,可以用类名.方法名()的形式访问由static标记的类方法。 ② 在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; } } public class TestPerson { public static void main(String[] args) { System.out.println("Number of total is " +Person.getTotalPerson()); //没有创建对象也可以访问静态方法 Person p1 = new Person(); System.out.println( "Number of total is "+ Person.getTotalPerson()); } }③ 因为不需要实例就可以访问static方法,因此static方法内部不能有this。(也不能有super ? YES!) ④ 重载的方法需要同时为static的或者非static的。
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(3); } }由于java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。
命令行参数用法举例 public class CommandPara { public static void main(String[] args) { for ( int i = 0; i < args.length; i++ ) { System.out.println("args[" + i + "] = " + args[i]); } } } //运行程序CommandPara.java java CommandPara "lisa" "bily" "Mr Brown"final修饰类
final class A{ } class B extends A{ //错误,不能被继承。 } Final修饰的类不能被继承final修饰方法
class A{ public final void print(){ System.out.println(“A”); } } class B extends A{ public void print(){ //错误,不能被重写。 System.out.println(“众软”); } } Final修饰的方法不能被子类重写final修饰变量——常量
class A{ private final String INFO = “众软”; //声明常量 public void print(){ //INFO = “众软”; } }常量名要大写,内容不可修改。 static final:全局变量
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
用abstract关键字来修饰一个类时,这个类叫做抽象类;用abstract来修饰一个方法时,该方法叫做抽象方法。 抽象方法:只有方法的声明,没有方法的实现。以分号结束:abstract int abstractMethod( int a );含有抽象方法的类必须被声明为抽象类。抽象类不能被实例化。抽象类是用来作为父类被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法。举例
abstract class A{ abstract void m1( ); public void m2( ){ System.out.println("A类中定义的m2方法"); } } class B extends A{ void m1( ){ System.out.println("B类中定义的m1方法"); } } public class Test{ public static void main( String args[ ] ){ A a = new B( ); a.m1( ); a.m2( ); } }应用 抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。 ① 在航运公司系统中,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( ) { //写出计算驳船行驶距离的具体方法} }抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。 解决的问题:
当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。 abstract class Template{ public final void getTime(){ 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(){ for(int i = 0;i<10000;i++){ System.out.println(i); } } }有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
接口(interface)是抽象方法和常量值的定义的集合。
从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
实现接口类:
class SubClass implements InterfaceA{ }一个类可以实现多个接口,接口也可以继承其它接口。
接口的特点: ① 用interface来定义。 ② 接口中的所有成员变量都默认是由public static final修饰的。 ③ 接口中的所有方法都默认是由public abstract修饰的。 ④ 接口没有构造器。 ⑤ 接口采用多层继承机制。
接口定义举例
public interface Runner { int ID = 1; void start(); public void run(); void stop(); }实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
接口的主要用途就是被实现类实现。(面向接口编程)
与继承关系类似,接口与实现类之间存在多态性
定义Java类的语法格式:先写extends,后写implements
< modifier> class < name> [extends < superclass>] [implements < interface> [,< interface>]* ] { <declarations>* }抽象类新增加新的抽象方法存在的问题
接口应用举例
接口应用举例
一个类可以实现多个无关的接口 interface Runner { public void run();} interface Swimmer {public double swim();} class Creator{public int eat(){…}} class Man extends Creator 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(); Man m = new Man(); t.m1(m); t.m2(m); t.m3(m); } public String m1(Runner f) { f.run(); } public void m2(Swimmer s) {s.swim();} public void m3(Creator a) {a.eat();} }接口的其他问题 ① 如果实现接口的类中没有实现接口中的全部方法,必须将此类定义为抽象类 接口也可以继承另一个接口,使用extends关键字。
interface MyInterface{ String s=“MyInterface”; public void absM1(); } 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中所有方法的实现。
FactoryMethod模式是设计模式中应用最为广泛的模式,在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。FactoryMethod解决的就是这个问题,它通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好的解决了这种紧耦合的关系。
举例