封装、继承、多态
面向对象三大特征:封装、继承、多态
一、 封装
Java的封装其实是合理隐藏、合理暴露,隐藏即隐藏内部实现细节,暴露即向外界暴露“操作界面”,这样做,可以使一个实例的内部细节不会被破坏,又具有可操作性。
(1) 封装重点:访问控制符→private、默认(不写)、protected、public
① private:类访问权限,被它修饰的成员,只能在该类中被访问;
② 默认(不写):包访问权限,被它修饰的成员,只能在该类以及该类所在的包中被访问;
③ protected:子类访问权限,被它修饰的成员,只能在该类、该类所在的包以及其子类中被访问;
④ public:公共权限,被它修饰的成员,可在任意地方被访问;
(2) 封装操作
① 将成员变量隐藏(private修饰);
② 为成员变量提供setter、getter方法(public修饰,setter方法有形参无返回值,getter方法无形参有返回值);
③ 需要暴露的方法用public修饰;
④ 如果希望一个方法主要用于被子类重写,用protected修饰;
(3) 封装示例:
class Worker {
//实例变量
private String name;
private int age;
private double salary;
//setter、getter方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getSalary() {
return salary;
}
//暴露的方法
public void live(String name,String words){
System.out.println(name + " said: " + words);
}
//供子类重写的方法
protected void working(String name,String job,int age){
System.out.println("name:" + name + "," + "job:" + job + "," + "age:" + age);
}
}
class WorkTest extends Worker{
//重写Worker类中的working()方法
@Override
public void working(String name,String job,int age){
age += new Random().nextInt(11);
System.out.println("name:" + name + "," + "job:" + job + "," + "age:" + age);
}
public static void main(String[] args) {
Worker w1 = new Worker();
//操作Worker类中封装的成员变量
w1.setName("Shakespeare");
w1.setAge(900);
w1.setSalary(500000.0);
System.out.println("name:"+ w1.getName()+";"+"age:"+ w1.getAge()+";"+"salary:"+ w1.getSalary());
//使用Worker类中暴露的live()方法
w1.live(w1.getName(),"to be or not to be,that's a question");
//使用WorkTest类中重写后的working()方法
WorkTest w2 = new WorkTest();
w2.working("Jack","painter",34);
}
}
二、 继承
Java的继承是类与类之间的关系(并不是对象和对象之间的关系) ,是一种由一般到特殊的关系,子类是一种特殊的父类。
(1) 继承要点:
① 关键字:extends[有扩展的意思,子类扩展了父类];
② 父类也叫超类、基类,子类也叫派生类;
③ 子类实例可以当做父类实例来使用,子类可获得父类的成员变量和方法;
④ Java是单继承,一个类只能有一个直接父类;
⑤ 所有类继承Object类;
(3) 继承示例:
class Human{
protected String name = "人类";
protected int headnumber = 1;
public void live(){
System.out.println("使用工具");
}
}
class Asian extends Human{
public String skincolor = "黄色";
public void smart(){
System.out.println("聪明");
}
}
class BlackPepple extends Human{
public String skincolor = "黑色";
public void dance(){
System.out.println("善舞");
}
}
class HumanTest{
public static void main(String[] args) {
Asian a1 = new Asian();
BlackPepple b1 = new BlackPepple();
//子类实例拥有父类的成员变量且可以有自己特有的变量[子类拥有父类的属性且可以拥有自己特有的属性]
System.out.println("是" + a1.name + ",有" + a1.headnumber + "个脑袋" + ",肤色是" + a1.skincolor);
System.out.println("是" + b1.name + ",有" + b1.headnumber + "个脑袋" + ",肤色是" + b1.skincolor);
//子类实例拥有父类的方法且可以有自己特有的方法[子类拥有父类的“行为特征”且可以拥有自己特有的“行为特征”]
a1.live();
a1.smart();
b1.live();
b1.dance();
}
}
三、 多态
同一类型的多个实例、在执行同一个方法,呈现出多种行为特征叫多态。
(1) 多态示例:
class Bird {
protected String name = "鸟";
public void fly(){
System.out.println("鸟在天上飞~~~");
}
}
class Sparrow extends Bird{
}
class Ostrich extends Bird {
@Override
public void fly() {
System.out.println("鸵鸟只能跑~~~");
}
}
public class BirdTest {
public static void main(String[] args) {
//子类对象赋值给父类变量
Bird b1 = new Sparrow();
Bird b2 = new Ostrich();
//同一个类的多个实例b1、b2,执行同一个方法,输出结果不同
b1.fly(); //输出“鸟在天上飞~~~” //动态绑定Sparrow类中的fly()方法,没有的话再向此类的父类中去寻找;
b2.fly(); //输出“鸵鸟只能跑~~~” //动态绑定Ostrich类中的fly()方法,没有的话再向此类的父类中去寻找;
/**
* 方法动态绑定:子类拥有父类的方法,子类实例调用某方法时若子类重写了该方法,优先使用子类自己重写的方法,若没有再去父类中寻找并使用
*/
}
}
(2) 多态下的特殊情况:
class Human{
protected String name = "人类";
protected int headnumber = 1;
public void live(){
System.out.println("使用工具");
}
}
class Asian extends Human{
public String skincolor = "黄色";
public void smart(){
System.out.println("聪明");
}
}
class BlackPepple extends Human{
public String skincolor = "黑色";
public void dance(){
System.out.println("善舞");
}
}
class HumanTest{
public static void main(String[] args) {
//子类对象赋值给父类变量
Human h1 = new Asian();
h1.live();
//h1.smart(); //----->此行编译报错
/**
* 问题:h1是new出来的Asian类的实例,Asian类中定义了smart()方法,为什么编译报错?
*/
}
}
问题:以上代码中h1是new出来的Asian类的实例,Asian类中定义了smart()方法,为什么编译报错?
解释:一个变量在编译时,Java只认声明时指定的类型,h1在声明时指定的类型是Human,Human类中没有smart()方法,所以报错。
修改后如下:
class HumanTest{
public static void main(String[] args) {
//h1在声明时指定的类型是Asian类,它是Human的子类,那么h1可使用Human类中的live()方法,也可以使用Asian类中的smart()方法。
Asian h1 = new Asian();
h1.live();
h1.smart();
//声明时是Human类,只能调用Human类中的live()方法,这种情况强转成Asian类后才能使用Asian类中的smart()方法。
Human h2 = new Asian();
h2.live();
Asian hh2 = (Asian) h2;
hh2.smart();
}
}
(3) 概念补充:
衡量一个变量需考虑两种类型:编译时类型、运行时类型(实际类型)。编译时类型是指声明该变量时指定的类型,例如以上代码Human h2 = new Asian();变量h2的声明时类型为Human;运行时类型(实际类型)是指该变量实际所引用的对象的类型,那h2的运行时类型为Asian,Java程序在编译阶段只认编译时类型。