封装 继承 多态
封装(从源头解决问题)
★它指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类提供的方法来实现对内部信息的操作和访问。可以使我们容易地修改类的内部实现,而无需修改使用了该类的客户代码。
继承(继承是多态的前提)
★继承的基本思想
基于某个父类的扩展,子类可以继承父类的所有属性和方法,也可以增加父类不具备的属性和方法。或者直接重写父类的某些方法。
让一个类继承另一个类需要用extends关键字
★方法的重写
当父类中的某个方法并不适用于子类时,就需要在子类中 重写 父类这个方法。
注意事项:
1、子类方法的返回值类型范围类型必须小于等于父类的范围
2、子类方法的权限必须大于等于父类方法的权限修饰符
权限比较
public>protected>(什么都不写)>private
3、@Override 写在方法前面,用来检测是否为有效的方法覆盖重写 它是一个可选的安全检测手段
★子类和父类继承关系中变量和方法的访问
在继承中,如果子类和父类成员变量重名,访问规则
直接通过子类对象访问成员变量:等号左边是谁就优先用谁,没有则向上找
间接通过成员方法访问成员变量:该方法属于谁就优先用谁,没有则向上找
在继承中,如果子类和父类成员方法重名,访问规则
创建的对象是谁就优先用谁,没有则向上找
注意事项:无论是成员变量还是成员方法,如果没有都是向上找父类,绝不可能向下找子类。
多态
多态就是同一操作(方法)作用于不同的对象时,可以有不同的解释,产生不同的执行结果。
方法的重载就是类的多态性
重载 与 重写 的区别
方法重载:是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表。
方法重写:是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型 。在继承中,如果子类和父类成员方法重名,访问规则
创建的对象是谁就优先用谁,没有则向上找
注意事项:无论是成员变量还是成员方法,如果没有都是向上找父类,绝不可能向下找子类
多态
多态就是同一操作(方法)作用于不同的对象时,可以有不同的解释,产生不同的执行结果。
方法的重载就是类的多态性
重载 与 重写 的区别
方法重载:是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表。
方法重写:是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型。
//未封装的宠物类
package cn.jbit.epet.inherit;
/**
* 宠物狗狗类
* @author administrator
*/
public class Dog {
String name = "无名氏"; // 昵称,默认值是"无名氏"
int health = 100; // 健康值,默认值是100,健康值在1-100之间,小于60为不健康
int love = 0; // 亲密度
String strain = "聪明的拉布拉多犬"; // 品种
/**
* 输出狗狗的信息
*/
public void print() {
System.out.println("宠物的自白:\n我的名字叫" + this.name +
",健康值是" + this.health + ",和主人的亲密度是"
+ this.love + ",我是一只 " + this.strain + "。");
}
}
package cn.jbit.epet.inherit;
/**
* 宠物企鹅
* @author administrator
*/
public class Penguin {
String name = "无名氏"; // 昵称
int health = 100; // 健康值
int love = 0; // 亲密度
String sex = "Q仔"; // 性别
/**
* 输出企鹅的信息。
*/
public void print() {
System.out.println("宠物的自白:\n我的名字叫" + this.name +
",健康值是" + this.health + ",和主人的亲密度是"
+ this.love + ",性别是 " + this.sex + "。");
}
}
package cn.jbit.epet.inherit;
public class TestPet {
public static void main(String[] args) {
Dog dog=new Dog();
dog.health=-1000;
dog.love=3;
dog.name="多多";
dog.strain="吉娃娃";
dog.print();
Penguin p=new Penguin();
p.health=-1000;
p.love=3;
p.name="Q仔";
p.sex="男";
p.print();
}
}
//封装后的宠物类
package cn.jbit.epet.inherit.after;
/**
* 宠物狗狗类
* @author administrator
*/
public class Dog {
private String name = "无名氏"; // 昵称,默认值是"无名氏"
private int health = 100; // 健康值,默认值是100,健康值在1-100之间,小于60为不健康
private int love = 0; // 亲密度
private String strain = "聪明的拉布拉多犬"; // 品种
public Dog(){}
public Dog(String name, int health, int love, String strain) {
super();
this.name = name;
this.health = health;
this.love = love;
this.strain = strain;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
if(health<0||health>100){
System.out.println("健康值应该在0至100之间,默认值为60。");
this.health=60;
return;
}
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
if(love<0||love>100){
System.out.println("亲密度应该在0至100之间,默认值为10。");
this.love=10;
return;
}
this.love = love;
}
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/**
* 输出狗狗的信息
*/
public void print() {
System.out.println("宠物的自白:\n我的名字叫" + this.name +
",健康值是" + this.health + ",和主人的亲密度是"
+ this.love + ",我是一只 " + this.strain + "。");
}
}
package cn.jbit.epet.inherit.after;
/**
* 宠物企鹅类
* @author administrator
*/
class Penguin {
private String name =null; // 昵称
private int health = 0; // 健康值
private int love = 0; // 亲密度
private String sex =null; // 性别
public Penguin() {
}
public Penguin(String name,int health,String sex){
this.name=name;
this.health=health;
this.sex=sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
if(health<0||health>100){
System.out.println("健康值应该在0至100之间,默认值为60。");
this.health=60;
return;
}
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
if(love<0||love>100){
System.out.println("亲密度应该在0至100之间,默认值为10。");
this.love=10;
return;
}
this.love = love;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
/**
* 输出企鹅的信息。
*/
public void print() {
System.out.println("宠物的自白:\n我的名字叫" + this.getName()
+ ",健康值是" + this.getHealth() + ",和主人的亲密度是"
+ this.getLove() + ",我的性别是 " + this.getSex() + "。");
}
}
package cn.jbit.epet.inherit.after;
import java.util.Scanner;
/**
* 领养宠物。
* @author administrator
*/
public class Test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("欢迎您来到宠物店!");
// 1、 输入宠物名称
System.out.print("请输入要领养宠物的名字:");
String name = input.next();
// 2、 选择宠物类型
System.out.print("请选择要领养的宠物类型:(1、狗狗 2、企鹅)");
switch (input.nextInt()) {
case 1:
// 省略选择狗狗
break;
case 2:
// 如果是企鹅,选择企鹅性别
System.out.print("请选择企鹅的性别:(1、Q仔 2、Q妹)");
int sexId=input.nextInt();
String sex="Q妹";
if(sexId==1)
sex="Q仔";
System.out.print("请输入企鹅的健康值(1~100之间):");
int health=input.nextInt();
// 创建企鹅对象并赋值
Penguin png=new Penguin();
png.setName(name);
png.setSex(sex);
png.setHealth(health);
//Penguin png=new Penguin(name, health, sex); //可以使用有参构造方法创建对象
// 输出企鹅信息
png.print();
break;
}
}
}
封装的意义就是增强类的信息隐藏与模块化,提高安全性。封装的主要作用也是对外部隐藏具体的实现细节,增加程序的安全性。
java4种权限修饰符
package staticDemo;
public class TestVoter {
public static void main(String[] args) {
Voter zhang=new Voter("张三");
Voter li=new Voter("李四");
Voter wang=new Voter("王五");
zhang.voteFor();
li.voteFor();
wang.voteFor();
for(int i=1;i<=97;i++){
Voter v=new Voter("v"+i);
v.voteFor();
}
Voter v101=new Voter("v101");
v101.voteFor();
}
}
package staticDemo;
/*
* 一群选民进行投票,每个选民只允许投一次票,并且当投票总数达到100时,就停止投票
* Voter:选民类
* */
public class Voter {
private static int count; // 所有选民都会改变同一个数据:投票次数
private static final int MAX_COUNT = 100; // 最大投票数100适用于所有选民
private String name;// 投票人姓名
public Voter(String name) {
this.name = name;
}
//投票
public void voteFor() {
if(count==MAX_COUNT){
System.out.println("投票活动已经结束");
return;
}else{
count++;
System.out.println(this.name + ":感谢您投票!");
}
}
}
//继承
package extendAnimal;
/**
* 宠物类,狗狗和企鹅的父类
*/
public class Pet {
private String name = "无名氏";// 昵称
private int health = 100;// 健康值
private int love = 20;// 亲密度
/**
* 无参构造方法
*/
public Pet() {
}
/**
* 有参构造方法
* @param name 昵称
*/
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
if(health<0||health>100){
System.out.println("健康值应该在0至100之间,默认值为60。");
this.health=60;
return;
}
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
if(love<0||love>100){
System.out.println("亲密度应该在0至100之间,默认值为10。");
this.love=10;
return;
}
this.love = love;
}
/**
* 输出宠物信息
*/
public void print() {
System.out.println("宠物的自白:\n我的名字叫" +
this.name + ",我的健康值是" + this.health
+ ",我和主人的亲密程度是" + this.love + "。");
}
}
package extendAnimal;
/**
* 狗狗类,宠物的子类
*/
public class Dog extends Pet {
private String strain="牧羊犬";// 品种
//无参构造方法
public Dog() {
}
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
}
package extendAnimal;
/**
* 企鹅类,宠物的子类
*/
public class Penguin extends Pet {
private String sex="Q仔";// 性别
//无参构造方法
public Penguin() {
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
package extendAnimal;
//测试类
public class Test {
public static void main(String[] args) {
// 1、创建宠物对象pet并输出信息
Pet pet = new Pet("贝贝");
pet.print();
// 2、创建狗狗对象dog并输出信息
Dog dog = new Dog();
dog.setName("多多");
dog.setHealth(90);
dog.setLove(80);
dog.setStrain("吉娃娃");
dog.print();
// 3、创建企鹅对象pgn并输出信息
Penguin pgn = new Penguin();
pgn.setName("大黑");
pgn.setHealth(98);
pgn.setLove(99);
pgn.setSex("Q妹");
pgn.print();
}
}
Java中的继承是指在一个现有类(父类)的基础上在构建一个新类(子类),子类可以拥有父类的成员变量以及成员方法(但是不一定能访问或调用,例如父类中private私有的成员变量以及方法不能访问和调用)。继承的作用就是能提高代码的复用性。子类拥有父类中的一切(拥有不一定能使用),它可以访问和使用父类中的非私有成员变量,以及重写父类中的非私有成员方法。必须符合is-a的关系例如:狗是动物的子类
方法重写和多态
public class Base {
public void method1(){
System.out.println("父类的实例方法");
}
public static void method2(){
System.out.println("父类的静态方法");
}
public Base method3(){
System.out.println("父类返回值类型为base的方法");
return new Base();
}
private void method4(){
System.out.println("父类的私有方法");
}
}
public class Sub extends Base{
//private void method1(){ //访问权限不能严于父类
//public static void method1(){ //父类的非静态方法不能被子类覆盖为静态方法
public void method1(){
System.out.println("子类的实例方法");
}
//public void method2(){ //父类的静态方法不能被子类覆盖为非静态方法
//子类可以定义与父类同名的静态方法,以便在子类中"隐藏"父类的静态方法
public static void method2(){
System.out.println("子类的静态方法");
}
//返回值类型相同或者是其子类
public Sub method3(){
System.out.println("子类返回值为Sub的方法");
return new Sub();
}
//父类的私有方法不能被子类覆盖,这样写可以,但是是独立的方法
public void method4(){
System.out.println("子类的私有方法");
}
}
1.重写规则之一:
访问修饰符的限制一定要不小于被重写方法的访问修饰符
比如:Object类有个toString()方法, 开始重写这个方法的时候我们总容易忘记Public修饰符, 出错的原因就是:没有加任何访问修饰符的方法具有包访问权限, Default访问权限小于Public访问权限, 所以编译器出错。
2、重写规则之二:
参数列表必须与被重写方法的相同。
重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。
3、重写规则之三:
C-1:返回类型必须与被重写方法的返回类型相同。
父类方法A:void catch(){} 子类方法 B:int catch(){} 两者虽然参数相同, 返回类型不同, 所以不是重写。
父类方法A:int catch(){} 子类方法 B:long catch(){} 返回类型虽然兼容父类, 但是不同就是不同, 所以不是重写。
4、重写规则之四:
重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常。
举个简单的例子:父类异常好比父亲偷盗抢掠、那么儿子不能比父亲更坏、要学好、自然异常就要少。虽然举得例子与社会主义核心价值观有冲突、但是比较形象。// 2016/12/10 10:55 bluetata 追記 add
5、重写规则之五:
如果一个方法不能被继承, 则不能重写它。
比较典型的就是父类的private方法。因为private说明该方法对子类是不可见的, 子类再写一个同名的方法并不是对父类方法进行复写(Override), 而是重新生成一个新的方法, 也就不存在多态的问题了。同理也可以解释final, 因为方法同样是不可覆盖的。
6、重写规则之六:
不能重写被标识为final的方法。
// 2016/12/01 17:05 bluetata 追記 add Start
final方法可以被继承, 但是不能被重写, 一个方法如果被final修饰, 那么也就意味着, 这个方法不会被改动(声明一个final方法的主要目的是防止方法的内容被修改)。
// 2016/12/01 17:12 bluetata 追記 add End
7、重写规则之七:
静态方法不能被重写。
《JAVA编程思想》中多次的提到:方法是静态的、他的行为就不具有多态性。静态方法是与类、而非单个对象相关联的。
父类的普通方法可以被继承和重写,不多作解释,如果子类继承父类,而且子类没有重写父类的方法,但是子类会有从父类继承过来的方法。静态的方法可以被继承,但是不能重写。如果父类中有一个静态的方法,子类也有一个与其方法名,参数类型,参数个数都一样的方法,并且也有static关键字修饰,那么该子类的方法会把原来继承过来的父类的方法隐藏,而不是重写。通俗的讲就是父类的方法和子类的方法是两个没有关系的方法,具体调用哪一个方法是看是哪个对象的引用;这种父子类方法也不在存在多态的性质。《JAVA编程思想》:只有普通的方法调用可以是多态的,静态方法是与类而不是与某个对象相关联。
Object类是所有类的父类
Object类常见的方法
1.getClass方法
final方法,获得运行时类型。一般情况,是对象调用,用作比对等操作。
2.toString方法
该方法用得比较多,一般子类都有覆盖,子类一般返回的是类对象名称。
3.clone方法
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。克隆的另一个意义,创建新对象的另类方式。
4.finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
5.hashCode方法
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
6.equals方法
该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
7.wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
8.notify方法
该方法唤醒在该对象上等待的某个线程。
9.notifyAll方法
该方法唤醒在该对象上等待的所有线程。
//使用多态为宠物看病
package cn.jbit.epet.override;
/**
* 狗狗类,宠物的子类。
* @author administrator
*/
public class Dog extends Pet {
private String strain="吉娃娃";// 品种
public Dog(){}
/**
* 有参构造方法。
* @param name 昵称
* @param strain 品种
*/
public Dog(String name, String strain) {
super(name);
this.strain = strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
public String getStrain() {
return strain;
}
public void print(){
super.print();
System.out.println("我是一只"+this.getStrain()+"犬。");
}
public void toHospital() {
this.setHealth(60);
System.out.println("打针、吃药");
}
}
package cn.jbit.epet.override;
public class Master {
// 给宠物看病
public void cure(Pet pet) {
if (pet.getHealth() < 50)
pet.toHospital();
}
}
package cn.jbit.epet.override;
/**
* 企鹅类,宠物的子类。
* @author administrator
*/
public class Penguin extends Pet {
private String sex;// 性别
/**
* 有参构造方法。
* @param name 昵称
* @param sex 性别
*/
public Penguin(String name, String sex) {
super(name);
this.sex = sex;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void print(){
super.print();
System.out.println("我的性别是"+this.getSex()+"。");
}
public void toHospital() {
this.setHealth(70);
System.out.println("吃药、疗养");
}
}
package cn.jbit.epet.override;
/**
* 宠物类,狗狗和企鹅的父类
*/
public class Pet {
private String name = "无名氏";// 昵称
private int health = 100;// 健康值
private int love = 20;// 亲密度
/**
* 无参构造方法
*/
public Pet() {
}
/**
* 有参构造方法
* @param name 昵称
*/
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
if(health<0||health>100){
System.out.println("健康值应该在0至100之间,默认值为60。");
this.health=60;
return;
}
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
if(love<0||love>100){
System.out.println("亲密度应该在0至100之间,默认值为10。");
this.love=10;
return;
}
this.love = love;
}
/**
* 输出宠物信息
*/
public void print() {
System.out.println("宠物的自白:\n我的名字叫" +
this.name + ",我的健康值是" + this.health
+ ",我和主人的亲密程度是" + this.love + "。");
}
public void toHospital() {
}
}
package cn.jbit.epet.override;
public class Test {
public static void main(String[] args) {
Pet dog=new Dog();
dog.setHealth(10);
dog.print();
System.out.println("*************************");
Master master=new Master();
master.cure(dog);
dog.print();
}
}
宠物饿了,主人需要为宠物喂食,使用多态实现该过程
不同宠物吃的东西不一样
不同宠物吃完东西后恢复健康值不一样
健康值达到100时,不需要继续喂食package cn.jbit.epet.override;
/**
* 狗狗类,宠物的子类。
* @author administrator
*/
public class Dog extends Pet {
private String strain="吉娃娃";// 品种
public Dog(){}
/**
* 有参构造方法。
* @param name 昵称
* @param strain 品种
*/
public Dog(String name, String strain) {
super(name);
this.strain = strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
public String getStrain() {
return strain;
}
public void print(){
super.print();
System.out.println("我是一只"+this.getStrain()+"犬。");
}
public void toHospital() {
this.setHealth(60);
System.out.println("打针、吃药");
}
/**
* 实现吃食方法。
*/
public void eat() {
if(getHealth()>=100){
System.out.println("狗狗"+this.getName() +"吃饱了,不需要喂食了!");
}else{
this.setHealth(this.getHealth()+3);
System.out.println("狗狗"+this.getName() + "吃饱啦!健康值增加3。");
}
}
}
package cn.jbit.epet.override;
/**
* 企鹅类,宠物的子类。
* @author administrator
*/
public class Penguin extends Pet {
private String sex;// 性别
/**
* 有参构造方法。
* @param name 昵称
* @param sex 性别
*/
public Penguin(String name, String sex) {
super(name);
this.sex = sex;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void print(){
super.print();
System.out.println("我的性别是"+this.getSex()+"。");
}
public void toHospital() {
this.setHealth(70);
System.out.println("吃药、疗养");
}
/**
* 实现吃食方法。
*/
public void eat() {
if(getHealth()>=100){
System.out.println("企鹅"+this.getName() +"吃饱了,不需要喂食了!");
}else{
this.setHealth(this.getHealth()+5);
System.out.println("企鹅"+this.getName() + "吃饱啦!健康值增加5。");
}
}
}
package cn.jbit.epet.override;
public class Master {
// 给宠物看病
public void cure(Pet pet) {
if (pet.getHealth() < 50)
pet.toHospital();
}
/**
* 主人给宠物喂食。
*/
public void feed(Pet pet) {
pet.eat();
}
}
package cn.jbit.epet.override;
/**
* 宠物类,狗狗和企鹅的父类
*/
public abstract class Pet {
private String name = "无名氏";// 昵称
private int health = 100;// 健康值
private int love = 20;// 亲密度
/**
* 无参构造方法
*/
public Pet() {
}
/**
* 有参构造方法
* @param name 昵称
*/
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
if(health<0||health>100){
System.out.println("健康值应该在0至100之间,默认值为60。");
this.health=60;
return;
}
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
if(love<0||love>100){
System.out.println("亲密度应该在0至100之间,默认值为10。");
this.love=10;
return;
}
this.love = love;
}
/**
* 输出宠物信息
*/
public void print() {
System.out.println("宠物的自白:\n我的名字叫" +
this.name + ",我的健康值是" + this.health
+ ",我和主人的亲密程度是" + this.love + "。");
}
public abstract void toHospital();
/**
* 抽象方法eat(),负责宠物吃饭功能。
*/
public abstract void eat();
}
package cn.jbit.epet.override;
public class Test {
public static void main(String[] args) {
Pet dog=new Dog();
dog.setHealth(80);
dog.print();
System.out.println("*************************");
Master master=new Master();
master.feed(dog);
dog.print();
}
}
转型
转型是在继承的基础上而言的,继承是面向对象语言中,代码复用的一种机制,通过继承,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
向上转型:子类引用的对象转换为父类类型称为向上转型。通俗地说就是是将子类对象转为父类对象。此处父类对象可以是接口
向下转型:父类引用的对象转换为子类类型称为向下转型