4.1 Java类的继承
1.类的继承
1)为描述和处理个人信息,定义类Person:
2)为描述和处理学生信息,定义类Student:
3)通过继承,简化Student类的定义:
4)类继承语法规则:
< 修饰符> class < 子类名称> [extends < 父类>] {
<属性和方法的声明>
}
5)Java只支持单继承,不允许多重继承
---一个子类只能有一个父类
---一个父类可以派生出多个子类
6)单继承举例:
7)子类继承了父类,就继承了父类的方法和属性。
在子类中,可以使用父类中定义的方法和属性,也可以创建新的数据和方法。
因而,子类通常比父类的功能更多。
8)在Java中,继承的关键字用的是“extends”,即子类不是父类的子集,而是对父类的“扩展”。
9)关于继承的规则:
子类不能继承父类中私有的(private)的成员变量和方法。
4.2访问控制
1.访问控制
可以对Java类中定义的属性和方法进行访问控制——规定不同的保护等级:public、protected、default、private
修饰符 | 同一个类 | 同一个包 | 子类 | 整体 |
private | Yes |
|
|
|
default | Yes | Yes |
|
|
protected | Yes | Yes | Yes |
|
public | Yes | Yes | Yes | Yes |
private:意思是私有的。这个访问控制修饰符的访问级别最低。使用关键字所进行的修饰的成员是不允许自身所在的类之外的其他类进行访问的。
default:意思是默认的。但是作为访问修饰符时,default指的是不加任何控制修饰符,并不是要使用关键字进行修饰。没有使用任一访问控制修饰符进行修饰的成员只能同一程序包中的类进行访问。
protected:意思是受保护的。使用这个访问控制修饰符进行修饰的成员只能由派生类或统一程序包中的类进行访问。对其他程序包的派生类而言,效果相当于共有的。对于其他程序的非派生类来说,效果相当于私有的。
public:意思是公有的、公共的。这个访问控制修饰符的访问级别最高。使用这个访问控制修饰符进行修饰的成员,被访问时不受任何限制。
注意:不能使用private和protected这两个访问控制修饰符去修饰类。
在应用程序设计上要遵循“尽可能保持数据的私有性”这个原则。
2.访问控制举例:
public class Parent {
private int f1=1;
int f2=2;
protected int f3=3;
public int f4=4;
private void fm1(){
System.out.println("in fm1() f1=" + f1);
}
void fm2() {System.out.println("in fm2() f2=" + f2);}
protected void fm3() {System.out.println("in fm3() f3=" + f3);}
public void fm4() {System.out.println("in fm4() f4=" + f4); }
}
public class Child extends Parent{
private int c1=21;
public int c2=22;
private void cm1(){System.out.println("in cm1() c1=" + c1);}
public void cm2(){System.out.println("in cm2() c2=" + c2);}
public static void main(String[] args) {
int i;
Parent p=new Parent();
i = p.f2;// i = p.f3; i = p.f4;
p.fm2();// p.fm3(); p.fm4();
Child c = new Child();
i = c.f2; // i = c.f3; i = c.f4;
c.fm2();//c.fm3(); c.fm4()
i = c.c1; // i = c.c2;
c.cm1(); //c.cm2(); c.fm2();
}
}
3.访问控制分析
父类Parent和子类Child在同一包中定义时:
4.3方法的重写、覆盖
1.覆盖方法
1)在子类中可以根据需要对从父类中继承来的方法进行改造-----覆盖方法(方法的重置、重写),在程序执行时,子类的方法将覆盖父类的方法。
2)覆盖方法必须与被覆盖方法具有相同的方法名称、参数列表和返回值类型。
3)覆盖方法不能使用比被覆盖方法更严格的访问权限。
2.覆盖方法举例
1)public class Person {
public String name;
public int age;
public String getInfo(){
return "Name: "+ name + "\n" +"age: "+ age;
}
}
public class Student extends Person{
public String school;
public String getInfo() { //覆盖方法
return "Name: "+ name + "\nage: "+ age
+ "\nschool: "+ school;
}
public static void main(String args[]){
Student s1=new Student();
s1.name="Bob";
s1.age=20;
s1.school="school2";
System.out.println(s1.getInfo()); //Name:Bob age:20 school:school2
}
}
2)public class Parent {
public void method1() {
}
}
public class Child {
private void method1() {
//非法,子类中的method1()的访问权限private比被覆盖方法的访问权限public弱
}
}
public class UseBoth {
public void doOtherThing() {
Parent p1 = new Parent();
Child p2 = new Child();
p1.method1();
// p2.method1();//非法,子类Child中的method1()的访问权限private比被覆盖方法的访问权限public弱
}
}
4.4super关键字
1.在Java类中使用super来引用父类的成分
---super可用于访问父类中定义的属性
---super可用于调用父类中定义的成员方法
---super可用于在子类构造方法中调用父类的构造方法
---super的追溯不仅限于直接父类
2.关键字super举例
public class Person {
public String name;
public int age;
public String getInfo(){
return "Name: "+ name + "\n" +"age: "+ age;
}
}
public class Student2 extends Person{
public String school="new school";
public String getSchool() {
return school;
}
public String getInfo() { //覆盖方法
return super.getInfo() + "\nschool: "+ school; //调用父类的方法
}
public static void main(String args[]){
Student2 s1=new Student2();
s1.name="Bob";
s1.age=20;
s1.school="school2";
System.out.println(s1.getInfo()); //Name:Bob age:20 school:school2
}
}
3.构造方法不能继承
1)子类继承父类所有的成员变量和成员方法,但不能继承父类的构造方法。
2)在一个Java类中可以通过两种方式获得构造方法
----使用系统默认的无参数构造方法
----显式定义一个或多个构造方法
3)一旦显式定义了构造方法,系统不再提供默认构造方法
4.构造方法不能继承
1)子类继承父类所有的成员变量和成员方法,但不继承父类的构造方法
2)在一个Java类中可以通过两种方式获得构造方法
---使用系统默认的无参数构造方法
---显式定义一个或多个构造方法
3)一旦显式定义了构造方法,则系统不再提供默认构造方法
5.调用父类构造方法
1)在子类的构造方法中可使用super(参数列表)语句调用父类的构造方法
2)如果子类的构造方法中没有显式地调用父类构造方法,也没有使用this关键字调用重载的其它构造方法,则系统默认调用父类无参数的构造方法
3)如果子类构造方法中既未显式调用父类构造方法,而父类中又没有无参的构造方法,则编译出错
6.子类对象的实例化过程
4.5多态性及其应用
1.多态性
1)多态——在Java中,子类的对象可以替代父类的对象使用
2)一个变量只能有一种确定的数据类型
3)一个引用类型变量可能指向(引用)多种不同类型的对象
Person p = new Student();
Object o = new Person();//Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对象
父类类型的变量可以指向子类的对象
4)一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
Student m = new Student();
m.school = “pku”; //合法,Student类有school成员变量
Person e = new Student();
e.school = “pku”; //非法,Person类没有school成员变量
属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误
2.虚拟方法调用(Virtual Method Invocation)
1)正常的方法调用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
2)虚拟方法调用(多态情况下)
Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法
3)编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。—— 动态绑定
3.多态性应用举例
方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法
public class Test {
public void method(Person e){
//······
e.getInfo();
}
public static void main(String[] args) {
Test t = new Test();
Student m = new Student();
t.method(m); //子类的对象m传送给父类类型的参数e
}
}
4.instanceof操作符
x instanceof A:检验x是否为类A的对象,返回值为boolean型。
要求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类及其子类对象
}
5.对象类型转换(Casting)
1)基本数据类型的Casting:
小的数据类型可以自动转换成大的数据类型
如long g=20; double d=12.0f
可以把大的数据类型强制转化(casting)成小的数据类型
如 floate f=(float)12.0 int a=(int)1200L
2)对Java对象的强制类型转换称为造型
---从子类到父类的类型转换可以自动进行
---从父类到子类的类型转换必须通过造型(强制类型转换)实现
---无继承关系的引用类型间的转换是非法的
---在造型前可以使用instanceof操作符测试一个对象的类型
3)对象类型转换举例
public class Test {
public void method(Person e){ //设Person类中没有getschool()方法
System.out.println(e.getschool); //非法,编译时错误
if(e instanceof Student){
Student me=(Student) e; //将e强制转换为Student类型
System.out.println(me.getschool);
}
}
public static void main(String[] args) {
Test t = new Test();
Student m = new Student();
t.method(m);
}
}
4.6Object类及其主要方法
1.Object类
1)Object类是所有Java类的根父类
2)如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类
public class Person { ... }
等价于:
public class Person extends Object { ... }
例:
method(Object obj){…}//可以接收任何类作为其参数
Object o=new Person;
method(o);
2.==操作符与equals方法的区别
1)==:引用类型比较引用(是否指向同一个对象);
Person p1=new Person(); Person p2=new Person();
if (p1==p2){…}
基本类型比较值:int a=5; if(a==6){…}
2)用“==”进行比较时,符号两边的数据类型必须一致(可自动转换的基本数据类型除外),否则编译出错
3)equals()方法是Object类的方法,由于所有类都继承Object类,也就继承了equals()方法。只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象。格式:obj1.equals(obj2)
4)特例:当用equals()方法进行比较时,对类File、String、Date及封装类(Wrapper Class)来说,是比较类型及内容而不考虑引用的是否是同一个对象。
原因:在这些类中覆盖了equals()方法
3.toString方法
1)toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。
2)在进行String与其它类型数据的连接操作时,自动调用toString()方法
Date now=new Date();
System.out.println(“now=”+now);
相当于 System.out.println(“now=”+now.toString());//now=Date@122345
3)可以根据需要在用户自定义类型中重写toString()方法
如String类重写了toString()方法,返回字符串的值
s1=“hello”;
System.out.println(s1);//相当于System.out.println(s1.toString());
在ToString1.java中的类A里覆盖toString方法,使其输出类A对象的cint属性值。
4)基本类型数据转换为String类型时,调用了对应封装类的toString()方法
int a=10; System.out.println(“a=”+a);
4.封装类
针对八种基本定义相应的引用类型---封装类
基本数据类型 | 封装类 |
boolean | Boolean |
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |