类的封装,继承,多态
本篇将详细介绍JAVA编程的核心技术
类的封装,继承,多态是面向对象的三大特性。
封装:相当于一个黑匣子,放在黑匣子里
封装
将描述某类事物的数据与处理这些数据的函数封装在一起,形成一个有机整体,称为类
封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节
封装的实现
JAVA访问权限修饰符
私有(private)
1.类:只有内部类允许私有,只能在当前类中被访问
2.属性:只能被当前类访问
3.方法:只能被当前类访问
默认(default)
1.类:可以被当前包中所有类访问
2.属性:可以被相同包中的类访问
3.方法:可以被相同包中的类访问
保护(protected)
1.类:只有内部类可以设为保护权限,相同包中的类及其子类可以访问
2.属性:可以被相同包中的类以及子类访问
3.方法:可以被相同包中的类以及子类访问
公有(public)
1.类:可以被所有类访问
2.属性:可以被所有类访问
3.方法:可以被所有类访问
继承
某一新类A继承某一既有类B时,表示这个新类A具有B类的所有成员,同时又可对既有类的成员做出修改,或是增加了新的成员。前半部分是继承,后半部分是派生。
既有类称为:基类,超类,父类
新类称为:派生类,子类
继承的基本概念
class 子类名 extends 父类
/**
* @author 86152
*练习,继承
*/
class person{
int age;
String name;
person(String name,int age) //需要写构造方法,才能将姓名和年龄传进来
{
this.age=age;
this.name=name;
}
public void speak()
{
System.out.println("My name is "+name+" and my age is "+age);
}
}
class student extends person
{
String school;
student(String name,int age,String school){
super(name,age); //super关键字,继承姓名和年龄
this.school=school;
}
void study()
{
System.out.println("I am studying in "+school);
}
}
public class demo {
public static void main(String []args)
{
student ming= new student("ming",21,"ND");
ming.speak();
ming.study();
}
}
继承的限制
限制1:Java中不允许多重继承,但允许多层继承
限制2:从父类继承的私有成员,不能被子类直接使用
限制3:子类在进行对象初始化时,从父类中继承而来的数据成员需要先调用父类的构造方法来初始化,然后再用子类的构造方法来初始化本地的数据成员。
限制4:被final修饰的类不能再被继承
深度认识类的继承
子类对象的实例化过程:见:继承的限制-限制3
super关键字的使用
在“练习,继承”中,super(name,age),指名调用的是父类中含有两个参数的构造方法。
调用super必须写在子类构造方法的第一行,否则编译不通过。
super关键字不仅可用于调用父类中的构造方法,也可调用父类的属性或方法
/**
* @author 86152
*练习,super调用父类的属性和方法
*/
class person{
int age;
String name;
person() //这种super的使用,不需要重写构造方法
{
}
public void speak()
{
System.out.println("My name is "+name+" and my age is "+age);
}
}
class student extends person
{
String school;
student(String name,int age,String school){
//super(name,age); //super关键字,继承姓名和年龄
super.name=name;
super.age=age;
this.school=school;
}
void study()
{
System.out.println("I am studying in "+school);
}
}
public class demo {
public static void main(String []args)
{
student ming= new student("ming",21,"ND");
ming.speak();
ming.study();
}
}
限制子类的访问
/**
* @author 86152
*练习,子类访问父类的私有成员
*/
class person{
private int age;
private String name;
person(int age,String name) //重写构造方法
{
this.age=age;
this.name=name;
}
public void setarr(int age,String name)//该函数和构造函数的不同在于,构造方法是在实例化对象加载时运行一次且仅运行一次,该方法可以之后对属性再次修改
{
this.age=age;
this.name=name;
}
public void speak()
{
System.out.println("My name is "+name+" and my age is "+age);
}
}
class student extends person
{
String school;
student(String name,int age,String school){
super(age,name); //super关键字,继承姓名和年龄
this.school=school;
}
/*void try()
{
System.out.println("尝试访问父类的私有变量 "+name);
}*/
void study()
{
System.out.println("I am studying in "+school);
}
}
public class demo {
public static void main(String []args)
{
student ming= new student("ming",21,"ND");
ming.speak();
ming.setarr(30, "fang");
ming.speak();
}
}
覆写
子类在继承父类时,重复定义了父类的属性,或者重复实现了父类的方法(名称,参数个数,类型,返回值类型等完全一致)
/**
* @author 86152
*练习,子类覆写父类方法
*/
class person{
private int age;
private String name;
person(int age,String name) //重写构造方法
{
this.age=age;
this.name=name;
}
public void setarr(int age,String name)//该函数和构造函数的不同在于,构造方法是在实例化对象加载时运行一次且仅运行一次,该方法可以之后对属性再次修改
{
this.age=age;
this.name=name;
}
public String speak()
{
return "My name is "+name+" and my age is "+age;
}
}
class student extends person
{
String school;
student(String name,int age,String school){
super(age,name); //super关键字,继承姓名和年龄
this.school=school;
}
public String speak()
{
return super.speak()+".I am studying in "+school;//调用父类的方法
}
}
public class demo {
public static void main(String []args)
{
student ming= new student("ming",21,"ND");
System.out.println(ming.speak());
ming.setarr(30, "fang");
System.out.println(ming.speak());
}
}
覆写的注意点:
1.覆写方法的返回值和被覆写的方法的返回值相同
2.被覆写的方法不能是静态的
3.被覆写方法的访问权限应大于或等于覆写的访问权限
父类方法:public 子类方法:public
父类方法:default 子类方法:public,default,protected
父类方法:protected 子类方法:public,protected
父类方法:private 无法构成覆写,因为该方法对于子类来说不可见
多态
1.方法多态性,体现在方法的重载与覆写上。
方法的重载:同一个方法名称,根据传参的不同,所调用的方法体不同。
方法的覆写:父类的一个方法名称,在不同子类中有不同的功能实现。根据实例化子类的不同,同一个方法可以完成不同的功能。
2.对象多态性,体现在夫,子类的转型上
(1)向上转型
父类 父类对象=子类实例
(2)向下转型
子类 子类对象=父类实例
多态的核心概念:子类对象可以视作父类对象
多态的基本概念
/**
* @author 86152
*练习,多态
*/
class person{
private int age;
private String name;
person(int age,String name) //重写构造方法
{
this.age=age;
this.name=name;
}
public void speak1()
{
System.out.println("----父类speak1-------");
}
public void speak2()
{
System.out.println("----父类speak2-------");
}
}
class student extends person //多态实现必要条件:继承
{
String school;
student(String name,int age,String school){
super(age,name);
this.school=school;
}
public void speak1() //多态实现必要条件:覆写
{
System.out.println("----子类speak1-------");
}
public void speak2()
{
System.out.println("----子类speak2-------");
}
}
class greatstudent extends student
{
greatstudent(String name,int age,String school)
{
super(name,age,school);
}
public void speak1() //多态实现必要条件:覆写
{
System.out.println("----子子类speak1-------");
}
public void speak2()
{
System.out.println("----子子类speak2-------");
}
}
public class demo {
public static void main(String []args)
{
person p= new greatstudent("ming",21,"ND"); //多态实现必要条件:向上继承
p.speak1();
p.speak2();
}
}
方法多态性
即重载
对象多态性
1.向上转型
可以自动完成
2.向下转型
必须强制类型转换
/**
* @author 86152
*练习,父类对象找不到子类的扩充方法
*/
class person{
private int age;
private String name;
person(int age,String name) //重写构造方法
{
this.age=age;
this.name=name;
}
public void speak1()
{
System.out.println("----父类speak1-------");
}
public void speak2()
{
System.out.println("----父类speak2-------");
}
}
class student extends person //多态实现必要条件:继承
{
String school;
student(String name,int age,String school){
super(age,name);
this.school=school;
}
public void speak1() //多态实现必要条件:覆写
{
System.out.println("----子类speak1-------");
}
public void speak2()
{
System.out.println("----子类speak2-------");
}
public void speak3()
{
System.out.println("----子类speak3-------");
}
}
public class demo {
public static void main(String []args)
{
person p= new student("ming",21,"ND"); //多态实现必要条件:向上继承
p.speak1();
p.speak2();
// p.speak3();错误,speak3()是子类新写的方法,父类是无法使用的
}
}
隐藏
如果不想父类的方法被覆写应该怎么办呢?
使用关键词static ,static修饰的静态方法不能被覆盖。
所有的静态方法隶属于类,而非对象,因此可以通过“类名.静态方法名”的方法直接访问静态方法
/**
* @author 86152
*练习,隐藏
*/
class father{
public static void speak()
{
System.out.println("father overwirting...");
}
}
class son extends father
{
public static void speak()
{
System.out.println("son overwriting...");
}
}
public class demo {
public static void main(String []args)
{
father f=new son();
f.speak();
father.speak();//本例中希望大家关注的点
son.speak();
}
}
提高部分
1.重载和覆写的区别是什么?
从定义,使用范围,访问权限不同
重载:在一个类中,对与类名相同的构造方法进行重写,主要体现在在参数列表的(类型,个数,位置)的不同,对于访问权限没有特殊要求
覆写:在子类和父类当中,对于继承自父类的方法进行重写,重写要求方法名,参数,返回类型等都是相同的,子类方法的访问权限要比父类的访问权限更宽或者相同。
2.this和super的区别
从查找范围,调用的构造方法不同
this先查本类的属性和方法,在查父类的属性和方法。调用自己类的构造方法。
super直接调用父类的属性和方法。由子类调用父类构造方法。
3.final关键字的使用
final可以用来修饰类,方法,变量
1.final修饰的类不能有子类
2.final修饰的方法不能被覆写
3.final修饰的变量就成了常量
练习部分
- 建立一个人类(Person)和学生类(Student),功能要求如下。
⑴ Person中包含4个数据成员name、addr、sex和age,分别表示姓名、地址、类别和年龄。设计一个输出方法talk()来显示这4种属性。
⑵ Student类继承Person类,并增加成员Math、English存放数学与英语成绩。用一个6参构造方法、一个两参构造方法、一个无参构造方法和覆写输出方法talk()用于显示6种属性。对于构造方法参数个数不足以初始化4个数据成员时,在构造方法中采用自己指定默认值来实施初始化。
/**
* @author 86152
*练习,封装,继承,多态
*/
class person{
public person() {
this.name="小红";
this.addr="上海";
this.sex="女";
this.age=20;
}
public person(String name, String addr, String sex, int age) {
this.name = name;
this.addr = addr;
this.sex = sex;
this.age = age;
}
String name;
String addr;
String sex;
int age;
public void talk()
{
System.out.println("我的名字是"+name+".我住在"+addr+".我的性别是"+sex+".我今年"+age+"岁。");
}
}
class student extends person
{
public student(double math,double english)
{
super();
this.math=math;
this.english=english;
}
public student(String name,String addr,String sex,int age,double math,double english)
{
super(name,addr,sex,age);
this.math=math;
this.english=english;
}
double math;
double english;
public void talk()
{
super.talk();
System.out.println("我的英语成绩是"+english+"我的数学成绩是"+math);
}
}
public class demo {
public static void main(String []args)
{
student s=new student("小明","南京","男",30,95,90);
student s2=new student(80,75);
s.talk();
s2.talk();
}
}
定义一个Instrument(乐器)类,并定义其公有方法play(),再分别定义其子类Wind(管乐器), Percussion(打击乐器),Stringed(弦乐器),覆写play方法,实现每种乐器独有play方式。最后在测试类中使用多态的方法执行每个子类的play()方法。
/**
* @author 86152
*练习,封装,继承,多态
*/
class instrument{
public void play()
{
System.out.println("-------发出乐器声--------");
}
}
class wind extends instrument
{
public void play()
{
System.out.println("-------发出乐器声 管弦乐--------");
}
}
class percussion extends instrument
{
public void play()
{
System.out.println("-------发出乐器声 击打乐器--------");
}
}
class stringed extends instrument
{
public void play()
{
System.out.println("-------发出乐器声 弦乐器--------");
}
}
public class demo {
public static void main(String []args)
{
instrument in=new instrument();
wind wi =new wind();
percussion per=new percussion();
stringed str=new stringed();
in.play();
in=wi;
in.play();
in=per;
in.play();
in=str;
in.play();
}
}