目录
一、继承
1、继承的基本概念
继承是从已有的类创建新类的过程。
继承是面向对象三大特征之一;
被继承的类称为父类(超类),继承父类的类称为子类(派生类);
继承是指一个对象直接使用另一对象的属性和方法;
通过继承可以实现代码重用;
继承一个父类,只能继承非私有的数据(属性和方法)
protected(受保护的访问权限修饰符),在继承关系中使用,在父类中使用protected修饰的属性或方法可以被子类继承。
public class Test1{
public static void main(String[] args){
HomeDog homeDog = new HomeDog();
homeDog.print();
HomeDog homeDog1 = new HomeDog("旺财");
homeDog1.print();
}
}
class Dog{
protected String name;
private String sex;
public Dog(){
System.out.println("我是Dog的构造方法");
}
public void eat(){
System.out.println("吃饭");
}
}
class HomeDog extends Dog{
public HomeDog (String name){
this.name=name;
System.out.println("我是HomeDog 的构造方法");
}
public void print(){
System.out.println(name+"我是一只家狗");
}
}
class HuskyDog extends Dog{
public HuskyDog (){
System.out.println("我是HuskyDog 的构造方法");
}
public void show(){
System.out.println(name+"我是husky");
}
}
2、继承的限制
java只能实现单继承,也就是一个类只能有一个父类;
允许多层继承,即:一个子类可以有一个父类,一个父类还可以有其他父类;
继承只能继承非私有的属性和方法;
构造方法不能被继承;
注意:创建子类对象时,父类的构造方法也会被调用,这是因为子类要使用父类的数据,就需要通过父类的构造方法来初始化数据。
如果创建子类对象时会调用父类的默认构造方法;
3、继承小结
继承是发生在多个类之间;
继承使用关键字extends;
Java只能单继承,允许多层继承;
被继承的类称为父类(超类),继承父类的类称为子类(派生类);
在父类中非私有属性和方法可以被子类继承;
protected(受保护的访问权限修饰符),修饰的属性或方法可以被子类继承;
构造方法不能被继承;
创建对象会调用构造方法,调用构造方法不一定就是创建该类对象;
实例化子类对象,会先调用父类的构造方法,如果父类中没有默认的构造方法,那么子类必须显示的通过super(...)来调用父类带参的构造方法,super也只能在子类构造方法中的第一句;
继承的好处:
提高代码的复用性;
提高代码的维护性;
让类与类之间产生关系,是多态的前提;
继承的缺点:
增强了类与类之间的耦合性;
开发原则:高内聚,低耦合。
二、方法重写与super关键字
1、方法的重写
在java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但是有时子类并不想原封不动地继承父类的方法,而是想做一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
在子类和父类中,重写方法后,在调用时,以创建的对象类型为准,会调用谁的方法。
public class Test1{
public static void main(String[] args){
HomeDog homeDog = new HomeDog();
homeDog.print();
homeDog.eat();
}
}
class Dog{
protected String name;
private String sex;
public Dog(){
System.out.println("我是Dog的构造方法");
}
public void eat(){
System.out.println("吃饭");
}
}
class HomeDog extends Dog{
public HomeDog (String name){
super(name,"公");
System.out.println("我是HomeDog 的构造方法");
}
public void print(){
System.out.println(name+"我是一只家狗");
}
// 方法重写
public void eat(){
super.eat();//调用父类的方法
System.out.println("我是一只家狗,我喜欢吃骨头");
}
}
2、关于方法重写的一些特性
发生在子父类中,方法重写的两个方法返回值、方法名、参数列表必须完全一致(子类重写父类的方法);
子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常);
子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别);
父类中的方法若使用private、static、final任意修饰符,那么,不能被子类重写;
3、重写方法目的
若子类从父类中继承过来的方法,不能满足子类特有的需求时,子类就需要重写父类中相应的方法,方法的重写也是程序扩展的体现。
面试题:overloading与overriding区别,重载与重写的区别:
重载:发生在同一个类中,方法名相同,参数列表不同,与返回值无关
重写:发生在字符类中,方法名相同,参数列表相同,返回值相同,子类的访问修饰符要大于或等于父类的访问修饰符,子类的异常声明必须小于或等于父类的异常声明,如果方法被private,static,final修饰,不能被子类重写。
4、super关键字
使用super调用父类中的属性,可以从父类实例处获得信息;
使用super调用父类中的方法,可以委托父类对象帮助完成某件事情;
使用super调用父类中的构造方法(super形式),必须在子类构造方法的第一条语句,调用父类中相应的构造方法,若不显示的写出来,默认调用父类的无参构造方法,比如:super();
this表示当前对象;
使用super来调用父类的属性、方法和构造方法;
三、继承的应用示例
1、实现一个化妆品商城中的化妆品管理
i、定义一个化妆品类(Cosmetic)
ii、定义一个化妆品管理类(CosmeticManager)
(1) 实现进货功能
(2) 可以输出所有化妆品信息功能
iii、使用继承实现一个可按单价排序输出所有化妆品的功能
iv、使用继承实现一个只输出进口化妆品的功能
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
ImportCosmeticManager cm = new ImportCosmeticManager();
cm.add(new Cosmetic("香奈儿","进口",1000));
cm.add(new Cosmetic("圣罗兰","进口",800));
cm.add(new Cosmetic("大宝","国产",20));
cm.add(new Cosmetic("万紫千红","国产",15));
cm.printInfo();
}
}
//只输出进口的化妆品的管理类
class ImportCosmeticManager extends CosmeticManager{
public void printInfo(){
for(int i=0;i<count;i++){
//确定的东西放在前面,避免空指针的错误
if("进口".equals(cs[i].getType())){
System.out.println(cs[i].getInfo());
}
}
}
}
// 可按单价排序的化妆品管理类
class SortCosmeticManager extends CosmeticManager{
//排序输出所有的产品
public void printInfo(){
Cosmetic[] temp = Arrays.copyOf(cs,count);
// System.out.println(temp.length);
Cosmetic c=null;
for(int i=0;i<temp.length-1;i++){
for(int j=0;j<temp.length-i-1;j++){
if(temp[j].getPrice()>temp[j+1].getPrice()){
// temp[j]=temp[j]+temp[j+1];
// temp[j+1]=temp[j]-temp[j+1];
// temp[j]=temp[j]-temp[j+1];
c=temp[j];
temp[j]=temp[j+1];
temp[j+1]=c;
}
}
}
for (Cosmetic cosmetic:temp){
System.out.println(cosmetic.getInfo());
}
}
}
//化妆品管理类
class CosmeticManager{
protected Cosmetic[] cs = new Cosmetic[4];
protected int count = 0;
//进货功能
public void add(Cosmetic c){
int size = cs.length;
if(count>=size){
int newLen = size*2;
cs = Arrays.copyOf(cs,newLen);
}
cs[count] = c;
count++;
}
//输出所有产品
public void printInfo(){
for (int i=0;i<count;i++){
System.out.println(cs[i].getInfo());
}
}
}
//化妆品类
class Cosmetic{
private String name; //品牌
private String type; //进口或国产
private int price; //单价
public Cosmetic(){}
public Cosmetic(String name,String type,int price){
this.name=name;
this.type=type;
this.price=price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getInfo(){
return "name="+name+",type="+type+",price="+price;
}
}
四、final关键字
1、使用final关键字声明一个常量
修饰属性或者修饰局部变量(最终变量),也称为常量。
2、使用final关键字声明一个方法
该方法为最终方法,且只能被子类继承。但是不能被子类重写。
3、使用final关键字声明一个类
该类转变为最终类,没有子类,final修饰的类无法被继承。
4、在方法参数中使用final,在该方法内部不能修改参数的值(在内部类中解释)
/**
* final关键字
* 1、使用final声明一个属性,就是常量,常量的命名规则建议使用全大写,
* 常量必须在定义时或在构造器中初始化
*/
public class Test2 {
public static void main(String[] args) {
System.out.println(Contant.PERSON_NUM);
FinalClass fc = new FinalClass();
System.out.println(fc.DAY_NUMBER);
fc.setLength(12);
}
}
// 常量类(工具类)
class Contant{
public static final int PERSON_NUM=10;//前面加上private私有访问,public公共访问
}
final class FinalClass{
public final int DAY_NUMBER;//工作天数
public FinalClass(){
DAY_NUMBER=22;
}
public final void print(){
System.out.println("我是final方法");
}
public void setLength(final int size){
//此处的size被final修饰后不能修改
//size++;
System.out.println(size);
}
}
//final修饰的类无法被继承
//class SubClass extends FinalClass{
//final修饰的方法不能被重写
// public void print(){
// System.out.println("我是final方法");
// }
//}
五、抽象类与接口
1、抽象类的基本概念
很多具有相同特征和行为的对象可以抽象为一个类;很多具有相同特征和行为的类可以抽象为一个抽象类。
使用abstract关键字声明的类为抽象类。
public class Test3 {
public static void main(String[] args) {
Man man = new Man();
Women women = new Women();
man.move();
man.eat();
women.move();
women.eat();
//抽象类不能被实例化
//Animal animal= new Animal();
}
}
abstract class Animal{
public abstract void move();//方法的声明,抽象方法只有声明,没有实现
}
abstract class Person extends Animal{
public abstract void eat();
}
// 继承抽象类的具体类必须实现所有抽象方法
class Man extends Person{
public void move(){
System.out.println("我是男人,我爱跑步");
}
public void eat(){
System.out.println("我是男人,我爱吃肉");
}
}
class Women extends Person{
public void move(){
System.out.println("我是女人,我爱逛街");
}
public void eat(){
System.out.println("我是女人,我爱吃香蕉");
}
}
2、抽象类的规则
抽象类可以没有抽象方法,有抽象方法的类必须是抽象类;
非抽象类继承抽象类必须实现所有抽象方法;
抽象类可以继承抽象类,可以不实现父类抽象方法;
抽象类可以有方法实现和属性;
抽象类不能被实例化;
抽象类不能声明为final;
抽象类可以有构造方法;
3、接口
i、接口的定义格式:
interface 接口名称{
全局常量;
抽象方法;
}
public class Test4 {
public static void main(String[] args) {
}
}
interface IEat{
//public abstract void eat(); //接口中只能定义抽象方法
void eat();//简写,接口中定义的方法没有声明修饰符,默认为 public abstract
//public static final int NUM=10;//在接口中定义一个常量
int NUM=10;//简写 常量
//JDK1.8新特性,可以被所有实现类(继承接口的类)继承
public default void print(){
System.out.println("eat");
}
}
ii、接口的概念:
接口是一组行为的规范、定义,没有实现(JDK1.8默认方法,有一个可以实现)
使用接口,可以让我们的程序更加利于变化
接口是面向对象编程体系中的思想精髓之一
面向对象设计法则:基于接口编程
public class Test4 {
public static void main(String[] args) {
Girl girl = new Girl("小红");
girl.sleep();
girl.eat();
girl.run();
}
}
interface IEat{
void eat();
int NUM=10;
}
interface IRun{
void run();
}
//接口可以继承,并且可以实现多继承,但是类只能单继承
interface ISleep extends IEat,IRun{
void sleep();
}
//实现接口的类,也可以多实现,必须实现接口的所有方法
class Girl implements ISleep,IEat{
private String name;
public Girl(String name){
this.name=name;
}
public void sleep(){
System.out.println("我爱睡觉");
}
public void eat(){
System.out.println("我是"+name+",我爱吃猪脚");
}
public void run() {
System.out.println("吃完就跑");
}
}
iii、接口的使用规则:
(1) 定义一个接口,使用interface关键字;
(2) 在一个接口中,只能定义常量、抽象方法、JDK1.8后可以定义默认的实现方法;
(3) 接口可以继承多个接口;
(4)一个具体类实现接口使用implements关键字;
(5) 一个类可以实现多个接口;
(6)抽象类实现接口可以不实现接口的方法;
(7)在接口中定义的方法没有声明访问修饰符,默认为public;
(8)接口中不能有构造方法;
(9)接口不能被实例化;
iv、面向对象的设计原则:
对修改关闭,对扩展开放;修改以往的代码,设计到他人的调用,在开发中需要注意。
面向接口编程;在类与类之间有关系的时候,都要用来接口关联。