面向对象
继承:java的继承是通过extends关键字来实现,实现继承的类被称为子类,被继承的称为父类
语法格式:
修饰符 class SubClass extends SuperClass
{
//类定义部分
}
java的子类不能获得父类的构造器。
public class Fruit //父类
{
public double weight; //父类变量
public void info() /父类方法
{
System.out.println("我是一个水果! 重"+weight+“g”);
}
}
public class Apple extends Fruit //子类继承父类
{
public static void main (String[] args)
{
//创建Apple对象
Apple a = new Apple;
//Apple 本身没有weight成员变量
//因为继承了父Fruit的关系,也可以访问Apple对象的weight成员变量
a.weight = 56;
//调用Apple对象的info方法;
a.info();
}
}
java不支持多继承,但是支持多层继承
-
换句话说:每个类最多只能有一个直接父类,但可以有无限多个间接父类。
-
例如:
class Fruit extends Plant{...} //fruit继承Plant
class Apple extends Fruit{...} //Apple继承fruit
- 但如果并未指定这个类的直接父类 则默认 Java.lang.Object这个类为它的父类。(object是所有类的父类)
重写父类方法:有时候子类需要重写父类方法。
- 做法就是:在子类里重新定义父类的方法。则原本父类的方法将会被覆盖。要求“两同两小一大”原则。 两同:方法名 形参列表相同 两小 :子类方法的返回值硬币父类方法返回值类型更小或者相等,子类方法声明抛出的异常应比父类方法的小或者相等。一大:子类方法的访问权限应比父类方法的访问权限更大或者相等。而且 覆盖方法要么都是类方法 要么都是实例方法
- 重新调用父类被覆盖的方法。
- super关键字
- 用于 :用于调用子类在父类中继成得到的实例变量或者方法。super和tihs也不能够出现在statIic修饰的方法中
- 格式:super.方法名
- 当然如果父类的方法访问权限:private 则子类不能访问该方法。也无法重写该方法。
- 调用父类构造器:
- super调用;super调用的是父类的构造器 而this调用的同一个类中重载的构造器。但是super调用必须出现的子类构造器的第一行,this也是。
- 例如:
实例:
class Creature
{
public Craeature() //父类无参数构造器 隐式调用
{
System.out.println("Creature无参数构造器");
}
}
class Animal extends Creature
{
public Animal (String[] args )
{
System.out.println("Animal 带一个参数的构造器, "+"该动物的name为“+name);
}
public Animal(String name ,int age)
{
//this调用重载构造器
this(name);
System.out.println("Animal带俩个参数的构造器,"+ "其age为"+age);
}
}
public class wolf extends Animal
{
public wolf()
{
//显示调用父类有两个参数的构造器
super("灰太狼",3);
System.out.println("wolf无参数构造器");
}
public static void main(String[] args )
{
new wolf();
}
}
多态:Java引用类型有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译和运行时类型不一致就会出现多态。即相同变量,调用同一个方法时呈现多种不同的行为特征,这就是多态。
- 前提:
- 有继承关系
- 要有方法重写
- 要有父类引向子类
- 格式:
- fu f = new zi();
例:
Object p = new person();
通常来讲object是父类 person是子类 p只能调用object里的方法。而不能调用person里的方法。
对象的实例变量不具有多态性。
- 同一个对象在不同时刻体现出来的不同状态。
- 多态的前提:
- A:有继承或者实现关系。
- B:有方法重写。
- C:有父类或者父接口引用指向子类对象。
- 多态的分类:
- a:具体类多态
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
- b:抽象类多态
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
- c:接口多态
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
- 多态中的成员访问特点:
- A:成员变量
- 编译看左边,运行看左边
- B:构造方法
- 子类的构造都会默认访问父类构造
- C:成员方法
- 编译看左边,运行看右边
- D:静态方法
- 编译看左边,运行看左边
-多态的好处:
- 编译看左边,运行看左边
- A:提高代码的维护性(继承体现)
- B:提高代码的扩展性(多态体现)
- A:成员变量
- 多态的弊端:
- 父不能使用子的特有功能。
- 子可以当作父使用,父不能当作子使用。
- 多态中的转型
- A:向上转型:从子到父
- B:向下转型:从父到子 (强转)
引用变量的强制类型转换:
- 引用变量只能调用其编译时类型的方法。语法:(type)variable
- 注意:
- 基本类型之间的转换只能在数值类型之间进行
- 引用类型之间的转换只能在具有继承关系的两个类型之间进行。
异常:ClassCastException
当一个父类实例转换成子类实例类型,则这个对象必须实际上是子类实例才行(即即时编译为父类运行时类型为子类类型) 否则将在运行时引发ClassCastException异常。
- instanceof运算符:判断强制转换是否执行成功
例如可以将
String str = (String)objpri;
修改为:
if(objpri instanceof String)
{
String str = (String)objpri;
}
这样可以避免出现异常。
判断objpri是否是 String类 或者其子类 实现类的实例 如果是 返回true 否则返回false。
继承与组合
- 继承缺点:破坏封装
- 注意:为了父类有良好的封装性,不会因为继承而被子类随意更改,设计父类映注意以下要点:
-
1.尽量隐藏父类内部数据,尽量把父类所有的成员变量设置为 private访问类型,不要让子类直接访问父类的成员变量。
-
2.不要让子类随意访问 修改父类的方法。父类的工具方法都设置为private访问控制符修饰。如果父类的方法要被调用则必须以public来修饰,但又不希望子类重写父类的方法,可以用final修饰。如果希望父类的某个方法被重写 则可以用protected来修饰。
-
3.尽量不要在父类构造器中调用将要被子类重写的方法。
-
合适派生子类?
- 子类需要额外增加属性,而且不仅仅是属性值的改变。
- 子类需要增加自己独有的行为方式。
初始化块
格式:
修饰符{
//初始化块可执行性代码。。。。。。
}
- 修饰符:只能是static 使用static修饰的是静态初始化块。
- 初始化块里可以包含任何可执行性语句,包括变量,调用方法 循环 分支。。。。
java创建对象时,系统先为该对象的所有实例变量分配内存(前提是该类已被加载)接着初始化,顺序:先执行初始化块 在执行构造器的。 当有静态初始化块存在时,则在类初始化阶段就执行静态初始化块。
/*初始化块*/
class Root
{
static
{
System.out.println("Root 静态初始化块");
}
{
System.out.println("Root 普通初始化块");
}
public Root()
{
System.out.println("Root无参数构造器");
}
}
class Mid extends Root
{
static
{
System.out.println("Mid静态初始化块");
}
{
System.out.println("Mid普通初始化块");
}
public Mid()
{
System.out.println("Mid无参数构造器");
}
public Mid(String msg)
{
this();//this 调用Mid里无参数构造器 同一类里
System.out.println("Mid的带参数构造器,其参数值"+msg);
}
}
class Leaf extends Mid
{
static
{
System.out.println("Leaf静态初始化模块");
}
{
System.out.println("Leaf普通初始化模块");
}
public Leaf()
{
//super调用父类构造器
super("疯狂java讲义");
System.out.println("执行Leaf构造器");
}
}
public class Test
{
public static void main(String[] args)
{
new Leaf();
new Leaf();
}
}
运行结果:
Root 静态初始化块
Mid静态初始化块
Leaf静态初始化模块
Root 普通初始化块
Root无参数构造器
Mid普通初始化块
Mid无参数构造器
Mid的带参数构造器,其参数值疯狂java讲义
Leaf普通初始化模块
执行Leaf构造器
Root 普通初始化块
Root无参数构造器
Mid普通初始化块
Mid无参数构造器
Mid的带参数构造器,其参数值疯狂java讲义
Leaf普通初始化模块
执行Leaf构造器
由运行结果看出,初始化块的运行顺序是:
静态初始化块--》初始化块--》构造器