1. 什么是类、对象及之间的关系?
2. 谈谈你对构造函数的理解 ?
3. 静态初始化块与初始化块的区别?
4. 成员方法与静态方法的区别?
1. 什么是抽象类?
2. 什么是方法的重写?
1. 写出一个使用super关键字调用父类的方法的完成案例
2. 写出一个成员变量的隐藏的案例
3. 完成一个多态性的案例
4. 写代码测试当父类是抽象类,实例化子类时父类及子类中静态方法及构造方法的执行顺序是怎样的
5. 写出一个静态块、语句块、构造函数在继承中执行顺序是怎样的案例
1. package
2. import
3. 类的继承
4. 抽象类
5. 静态块、初始化块、构造函数在继承关系中的使用
为便于管理大型软件系统中数目众多的类,解决类的命名冲突问题,Java引入包(package)机制,提供类的多重类命名空间。
下面借由一张图来解释说明
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。它的格式为:
package pkg1[.pkg2[.pkg3…]];
package student.biggirl;
public class Beauty {
public void display(){
System.out.println("I’ve big eyes ");
}
}
备注:
Java编译器把包对应于文件系统的目录管理,package语句中,用”.”来指明包(目录)的层次;
为使用定义在不同包中的Java类,需用import语句来引入所需要的类。
语法格式:
import package1[.package2…]. (classname |*);
定义Beauty类
package student.biggirl.Beauty;
/**
* @author chj
*/
public class Beauty {
/**
* show方法
*/
public void show(){
System.out.println("show!!");
}
}
在不同的包中测试Beauty中的show方法:
package student.biggirl.Beauty.test;
import student.biggirl.Beauty.Beauty;
public class BeautyTest {
/**
* 入口方法
* @param args
*/
public static void main(String[] args) {
//创建对象
Beauty b = new Beauty();
//调用方法
b.show();
}
}
备注说明:
继承一般值得是指晚辈从父辈那里继承财产,也可以说是子女拥有父母所给予他们的东西。在面向对象程序设计中,继承的含义与此类似,所不同的是,这里继承的实体是类而非人。也就是说继承是子类拥有父类非私有的成员。
继承是面向对象三大特征之一,也是实现软件复用的重要手段
继承需要满足 is-a的关系
现实生活中的例子:
备注:引入网络图片.
继承分为单继承和多重继承。单继承是指一个子类最多只能有一个父类。多继承是一个子类可以有二个以上的父类。由于多继承会带来二义性,在实际应用中应尽量使用单继承。Java语言中的类只支持单继承,而接口支持多继承。Java中多继承的功能是通过接口(interface)来间接实现的[1]。
在java语言中,继承通过extends关键字来实现。也就是用extends指明当前类子类,并指明从哪个类继承而来的。即在子类的声明中,通过使用extends关键字来显式的指明其父类。
其基本的声明格式如下:
[修饰符]class 子类名 extends 父类名 [implements 接口名]{
//类体
}
//父类Animal类
public class Animal{
public String address = "动物园"
}
//子类Dog类
public class Dog extends Animal{
public static void main(String[] args) {
Dog dog = new Dog();
System.out.println("狗属于动物,在"+dog.address+"里");
}
}
/*可以看到,Dog类中没有address成员变量,
但是继承了父类Animal,所以当动物在动物园时,狗也在动物园*/
注意:
为描述和处理个人信息,定义类Person
代码如下:
public class Person {
public String name;
public int age;
public Date birth;
public String getInfo() {...}
}
为描述和处理学生信息,定义类Student
代码如下:
public class Student {
public String name;
public int age;
public Date birth;
public String school;
public String getInfo() {...}
}
通过继承,简化Student类的定义:
代码如下:
public class Student extends Person{
public String school;
}
多态机制是面向对象程序设计的最重要特征.
动态绑定是指”在执行过程中(而非编译期间)”,判断所引用的实际对象类型.
多态的特点是采用同名的方式,根据调用方法时传递的参数的多少以及传递参数类型的不同,调用不同的方法,这样对于类的编制而言,可以采用同样的方法获得不同的行为特征.
多态性
1. 编译时多态
表现为方法名相同,而参数列表不同。
典型:System.out.println(参数);它的参数有很多种.
2. 运行时多态
程序运行的时候判断到底是哪个类(父类还是子类的),进而确定实际调用的方法.
对象的多态性(子类对象和父类对象的相互转换关系)
如何实现多态
1. 要有继承
2. 要有重写
3. 父类的引用指向子类的对象
更具体的说明如下:
现实中的示例
备注:引入网路的图片
根据现实中的示例完成的代码示例1如下:
/*打印机*/
public class Printer {
public void print() {
System.out.println("普通打印!");
}
/**
* 根据不同的打印机 进行不同的打印
*
* @param printer
*/
public static void print(Printer printer) {
//可以讲解一下instanceof的使用
printer.print();
}
public static void main(String[] args) {
// 普通打印
print(new Printer());
// 彩色打印
print(new ColorPrinter());
// 黑白打印
print(new BwPrinter());
}
}
/**
* 彩色打印机
* @author change
*
*/
public class ColorPrinter extends Printer{
@Override
public void print() {
System.out.println("彩色打印!!!!!!");
}
}
/**
* 黑白打印机
* @author change
*
*/
public class BwPrinter extends Printer{
@Override
public void print() {
System.out.println("黑白打印!!!!!!");
}
}
运行结果如下
普通打印!
彩色打印!!!!!!
黑白打印!!!!!!
多态禁忌
千万不要出现以下操作:就是将父类对象转换成子类对象类型
Person p = new Person(); //Person是父类 Student是子类
Student stu = (Student) p;
//出现如下bug
/*Exception in thread "main" java.lang.ClassCastException:
day01.Person cannot be cast to day01.Student
at day01.Student.main(Student.java:10)*/
注意:正确操作:我们能转换的是父类的引用指向类自己的子类对象时,该引用可以被提升也可以被强制转换.
在Java中,super关键字有两个主要用途;
第一种用途是:在子类的构造方法中,super关键字可以显式地调用父类的构造方法,用于将参数传递给它;
其一般语法是:
super(实际参数);
需要注意的是:该语句必须是子类构造方法的第一条语句
如果父类的构造方法中包括参数,则参数列表为必选项,用于指定父类构造方法的入口参数。
第二种用途是:调用父类的成员变量及其成员属性;
其一般语法是:
super.成员名;
super.方法名([参数列表]);
前提条件是:父类中的该成员不是private的。
//父类Person类
class Person {
private String name;
public Person() {
System.out.println("构造器---person---");
}
public Person(String name) {
System.out.println("构造器---person---"+name);
}
}
//子类Student类
class Student extends Person{
public Student(String name) {
super(name);
System.out.println("构造器---student--"+name);
}
}
//测试类
public class Test{
public static void main(String[] args) {
Student stu = new Student("王三");
}
}
父类Parent中有成员变量A,子类Child定义了与A同名的成员变量B,子类对象ChildObj调用的是自己的成员变量B。
如果把子类对象ChildObj转换为超类对象ParentObj,ParentObj调用的是父类的成员变量A!
注:
1. 隐藏成员变量时,只要同名即可,可以更改变量类型(无论基本类型还是隐藏类型)
2. 不能隐藏超类中的private成员变量,换句话说,只能隐藏可以访问的成员变量。
3. 隐藏超类成员变量A时,可以降低或提高子类成员变量B的访问权限,只要A不是private
4. 隐藏成员变量与是否静态无关!静态变量可以隐藏实例变量,实例变量也可以隐藏静态变量。
5. 可以隐藏超类中的final成员变量。
class Animal {
char hairColor='B';
int legNumber=2;
static boolean isHuman=true;
public static void testClassMethod() {
System.out.println("The class" + " method in Animal.");
}
public void testInstanceMethod() {
System.out.println("The instance " + " method in Animal.");
}
}
public class Cat extends Animal {
static int hairColor=1;
char legNumber='A';
double isHuman=3.1415926E5;
public static void testClassMethod() {
System.out.println("The class method" + " in Cat.");
}
public void testInstanceMethod() {
System.out.println("The instance method" + " in Cat.");
}
public static void main(String[] args) {
System.out.println("========child class=========");
Cat myCat = new Cat();
System.out.println("myCat.hairColor="+myCat.hairColor);
System.out.println("myCat.legNumber="+myCat.legNumber);
System.out.println("myCat.isHuman="+myCat.isHuman);
myCat.testClassMethod();
myCat.testInstanceMethod();
System.out.println("========child class ---> parent class=========");
Animal myAnimal = myCat;
System.out.println("========parent class=========");
System.out.println("myAnimal.hairColor="+myAnimal.hairColor);
System.out.println("myAnimal.legNumber="+myAnimal.legNumber);
System.out.println("myAnimal.isHuman="+myAnimal.isHuman);
myAnimal.testClassMethod();
myAnimal.testInstanceMethod();
}
}
输出结果:
========child class=========
myCat.hairColor=1
myCat.legNumber=A
myCat.isHuman=314159.26
The class method in Cat.
The instance method in Cat.
========child class ---> parent class=========
========parent class=========
myAnimal.hairColor=B
myAnimal.legNumber=2
myAnimal.isHuman=true
The class method in Animal.
The instance method in Cat.
备注:引入网络案例.
父类中的构造方法不能被子类继承,即便它是public的;
父类的构造方法负责初始化属于它的成员变量,而子类的构造方法则只需考虑属于自己的成员变量,不必去关注父类的情况。
代码示例 1
class Person {
public Person() {
System.out.println("构造器---person---");
}
}
class Student extends Person{
public Student() {
System.out.println("构造器---student--");
}
}
public class Test{
public static void main(String[] args) {
Student stu = new Student();
}
}
输出结果:
构造器---person---
构造器---student--
代码示例 2
public class Person {
public Person(String str) {
System.out.println("构造器---person---"+str);
}
}
public class Student extends Person{
public Student() {
super("super");//如果父类中没有默认的构造函数,那么在子类的构造函数中 必须采用 super来进行处理
System.out.println("构造器---student--");
}
public static void main(String[] args) {
Student stu = new Student();
}
}
输出结果:
构造器---person---super
构造器---student--
构造器方法执行顺序:
继承的应用:
代码示例 3
public class Point {
protected float mx, my;
public Point(float mx, float my) {
this.mx = mx;
this.my = my;
}
public static void main(String[] args) {
Cycle cycle = new Cycle(2.5f);
}
}
class Cycle extends Point {
protected float mx;
public Cycle(float mx) {
this.mx = mx;
}
}
继承应用分析:
在实例化Circle类对象时,虚拟机一定会先调用其父类(Point类)的构造方法;
Point类的构造方法需要两个参数来初始化其成员,但此时并没有获得这两个参数,造成Point类的构造方法无法执行;
父类的构造方法执行失败从而导致子类(Circle类)的对象也无法创建;
问题的关键是:在实例化子类对象时,如何将参数传递给父类的构造方法?这就要使用到super关键字。
所以,代码可以修改为:
public class Point {
protected float mx, my;
public Point(float mx, float my) {
this.mx = mx;
this.my = my;
System.out.println("父类带参的构造方法");
System.out.println(mx+" "+my);
}
public Point(){
System.out.println("父类不带参的构造方法");
}
public Point(float mx){
System.out.println("父类带一个参 的构造函数");
System.out.println(mx);
}
public static void main(String[] args) {
Cycle cycle = new Cycle(2.5f);
}
}
class Cycle extends Point {
protected float mx;
public Cycle(float mx) {
super(mx);
}
}
方法重写时要遵循的规则:
注意
静态方法不能重写
//一 User类
class User {
public int test() {
return 0;
}
}
class Employee extends User {
public byte test() {
return 0;
}
}
//二 Bird类
class Bird {
public Object fly() {
return 0;
}
}
class Ostrich extends Bird {
public Byte fly() {
return 0;
}
}
//三 Bird类
class Bird {
public static int fly() {
return 0;
}
}
class Ostrich extends Bird {
public int fly() {
return 0;
}
}
观察三个例子,看是否是方法的重写
提示:
Byte是包装类型,byte是基本类型,两个可以互相转换。包装类型默认是null,而基本类型可能不是
//四 bird类
class Bird {
public int fly() {
return 1;
}
}
class Ostrich extends Bird {
public int fly() {
return 2;
}
}
//五 bird类
class Bird {
public static int fly() {
return 1;
}
}
class Ostrich extends Bird {
public static int fly() {
return 2;
}
}
//测试代码
public class OverTest {
public static void main(String[] args) {
Ostrich ostrich = new Ostrich();
System.out.println(ostrich.fly());
Bird bird = new Ostrich();
System.out.println(bird.fly());
}
}
问题1:通过代码测试,以上四和以上五重写了么?
扩展问题:方法重写与方法重载的区别?
用abstract关键字来修饰一个类时,这个类叫做抽象类
定义抽象类,语法格式如下:
abstact class 类名{
//类体
}
abstact class Animal{
public String type;
public Animal(){
tupe = "猫"
}
}
用abstract来修饰一个方法时,该方法叫做抽象方法
抽象方法只有方法的声明,而没有方法的实现,用abstract关键字进行修饰。声明一个抽象方法的基本格式如下:
abstract <方法返回值类型> 方法名(参数列表);
public abstract void Animal();
注意:抽象方法不能使用private 或 static 关键字进行修饰。
包含一个或多个抽象方法的类必须被声明为抽象类。因为抽象方法没有定义方法的实现部分,如果不声明为抽象类,这个类将可以生成对象,这时当用户调用抽象方法时,程序就不知道如何处理了
//使用abstract关键创建抽象类Animal,在该类中定义相应的变量和方法。
abstract class Animal {
public String type; //定义种类成员变量
//定义构造方法
public Animal(){
type="猫"; //对变量type进行初始化
}
//定义抽象方法
public abstract void zoo(); //把动物放动物园的方法。
}
//创建Animal的子类Cat类 ,并实现zoo()方法
public class Cat extends Animal {
@Override
public void zoo(){
System.out.println("猫进了动物园");
}
static {
System.out.println("加载Cat");
}
{
System.out.println("实例化Cat");
}
}
//创建Animal的子类Dog()类,并实现zoo()方法
public class Dog extends Animal{
@Override
public void zoo(){
System.out.println("把狗放进了动物园");
}
static {
System.out.println("加载Dog类");
}
{
System.out.println("实例化Dog类");
}
}
//创建一个包含main()方法的公共类Result,在该类中创建子类Cat和Dog实例。
public class Result {
public static void main(String[] args) {
System.out.println("调用Cat类的zoo()方法的结果是");
Cat cat = new Cat();
cat.zoo();
System.out.println("调用Dog类的zoo()方法的结果是");
Dog dog = new Dog();
dog.zoo();
}
}
输出结果:
调用Cat类的zoo()方法的结果是
加载Animal类
加载Cat类
实例化Animal
实例化Cat类
猫进了动物园
调用Dog类的zoo()方法的结果是
加载Dog类
实例化Animal
实例化Dog类
把狗放进了动物园
或者我们可以试试修改Reault类
public class Result {
public static void main(String[] args) {
//匿名类对象
new Animal() {
@Override
public void zoo() {
// TODO Auto-generated method stub
}
};
new Cat();
new Dog();
new Dog();
}
}
输出结果是:
加载Animal类
实例化Animal
加载Cat类
实例化Animal
实例化Cat类
加载Dog类
实例化Animal
实例化Dog类
实例化Animal
实例化Dog类
思考:
问题1:为什么抽象类不可以使用final关键字声明?
问题2:一个抽象类中可以定义构造器吗?
3.6.2 案例5
class Parent{
static String name = "hello";
{
System.out.println("3 parent block");
}
static {
System.out.println("1 parent static block");
}
public Parent(){
System.out.println("4 parent constructor");
}
}
class Child extends Parent{
static String childName = "hello";
{
System.out.println("5 child block");
}
static {
System.out.println("2 child static block");
}
public Child(){
System.out.println("6 child constructor");
}
}
public class StaticIniBlockOrderTest {
public static void main(String[] args) {
new Child();//语句(*)
}
}
输入结果:
1 parent static block
2 child static block
3 parent block
4 parent constructor
5 child block
6 child constructor
本章主要讲解了类的继承及其应用;抽象类的应用;静态块、初始化块、构造函数在继承关系中的使用。其中更扩展延伸出了super关键字,继承中的构造方法等知识点。
以上都是个人整理资料部分,有问题欢迎大家留言!如需转载,请注明出处!