一、面向对象九字真言:
找对象、搞对象、搞数据。
面向对象如何实现功能:
创建具有各种功能的对象,然后通过对象之间的相互作用,来实现最后的需求。
二、继承:
语法:
class 子类名称 extends 父类{
}
extends :关键字
继承:在子类中可以直接使用父类被继承的成员。就像是自己的一样。
扩展:重写父类的方法,自定义特有的方法。
被继承的类:父类、基类、超类
继承的类:子类、派生类、衍生类。
继承的概念:子类中包含了父类的成员,并可以在子类中使用的过程。
继承的优点:
1:代码、类的复用。
2:为了实现多态。
缺点:1:在一定程度上打破了封装。
2:父类中的私有的成员不能被子类继承,所有如果父类中的私有成员想被子类继承,那么必须扩大被访问的权限。就在某种程度上打破了封装性。
继承描述的是怎样的一种关系:是一种is-a 的关系。
不要随意的继承,只有两个类型之间的确是is-a 的关系的时候,才可以考虑使用继承。
例1:
/**
* 老师教学生
* 老师类: 姓名、年龄、性别,职称 教学生的功能 (可以让学生成绩提高)
*
* 学生类: 姓名,年龄,性别,成绩 学习功能 (可以让学生的成绩提高)
*
* 测试入口类:创建学生对象,老师对象, 打印学生信息(show 方法) 学生学习一下,老师教学一下。最后打印学生的信息show
* @author yhl
*
*/
public class TestInheritance {
public static void main(String[] args) {
MyStudent student = new MyStudent();
student.study();
student.show();
Teacher teacher = new Teacher();
teacher.teach(student);
student.show();
}
}
class Teacher extends Person{
private String title;
public Teacher() {
this("小杨老师",19,"男","初级讲师");
}
Teacher(String name, int age, String gender, String title) {
setName(name);
setAge(age);
setGender(gender);
setTitle(title);
}
void teach(MyStudent student){
int score = student.getScore();
student.setScore(score+1);
System.out.println(getName() + "\t 对 "+student.getName() + "\t授课,成绩从" +score + "提升到了:"+student.getScore());
}
public void show(){
System.out.println("name = "+getName() + "\tage = "+getAge() + "\tgender = "+getGender() +"\ttitle = "+title);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
class MyStudent extends Person{
private int score;
public MyStudent() {
this("李雷",20,"男",90);
}
MyStudent(String name, int age, String gender, int score) {
setName(name);
setAge(age);
setGender(gender);
setScore(score);
}
void study(){
System.out.println(getName() + "\t努力学习,成绩从 "+score ++ + "提高到了:"+score);
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public void show(){
System.out.println("name = "+getName() + "\tage = "+getAge() + "\tgender = "+getGender() +"\tscore = "+score);
}
}
class Person{
private String name;
private int age;
private String gender;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
例2:
import com.bjsxt.util.MyUtil;
//猫抓老鼠
//猫和老鼠都有智商的属性 名字的属性
//猫:抓老鼠
//老鼠:逃跑,死亡
//展示信息的功能
public class TestTomAndJerry {
public static void main(String[] args) {
Cat cat = new Cat(MyUtil.getRandomNumber(20, 101), "TOM");
Mouse mouse = new Mouse(MyUtil.getRandomNumber(0, 90), "JERRY");
cat.show();
mouse.show();
cat.catchMouse(mouse);
}
}
class Cat extends Animal{
public Cat() {
}
public Cat(int iq, String name) {
setIq(iq);
setName(name);
}
public void catchMouse(Mouse mouse){
if(this.getIq() > mouse.getIq()){
System.out.println(getName() + "\t抓住了 "+mouse.getName());
mouse.die();
}else{
System.out.println(getName() + "\t没有抓住 "+mouse.getName());
mouse.run();
}
}
}
class Mouse extends Animal{
public Mouse() {
}
public Mouse(int iq, String name) {
setName(name);
setIq(iq);
}
public void run(){
System.out.println(getName() + "\t逃跑了");
}
public void die(){
System.out.println(getName() + "\t 被抓住了,挂了!");
}
}
class Animal{
private int iq;
private String name;
public int getIq() {
return iq;
}
public void setIq(int iq) {
this.iq = iq;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name = "+name + "\tiq = "+iq);
}
}
java只支持单重继承。
解释:java 规定不允许一个类有多个直接的父类,只能有一个直接的父类。
但是c++ 是允许一个类有多个直接的父类的。
直接多继承的隐患:如果多个父类中存在同名的方法,可能子类在使用父类的同名的方法的时候,存在语义上冲突问题。
//间接的多重继承
class A extends B{
}
class B extends C{
}
不支持多重继承的缺点:扩展类的时候不如支持多重直接继承方便。
优点:去掉了c++ 直接多重继承的安全隐患。
父类的哪些成员可以被继承:
1:子类父类在同一个包下。
除了私有的成员,都可以被子类继承。
2:子类父类不在同一个包下
私有的,默认的,都不能被子类继承。
Public、protected 的可以被子类继承。
注意:1:构造方法不能被继承。
2:静态的成员能不能被继承:
静态成员可以被子类继承,只要访问的权限够即可。
被子类继承的静态的成员,可以使用父类的名称调用,也可以使用子类的名称直接调用访问。
三、Object类
java.lang.Object
public class Object类
Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
所有类的祖宗。
在java 中所有的类 除了 Object 类都直接的或者间接的继承了 Object类。
除了Object 类 的类都是 Object 类的子类。
如果一个类没有显式的继承任何的类,那么该类将被隐式的继承Object类。是Object类的直接的子类。
Object 类的9个方法:
clone(): 复制对象的。
getClass():返回对象的大 Class 对象。
equals(): 比较两个对象是否相等。
finalize():垃圾回收被调用的方法。
toString(): 得到当前对象的字符串表示形式。
hashCode():得到对象的哈希码。
notify():唤醒线程。
notifyAll():唤醒所有的线程。
wait():让线程等待。
四、方法的重写
方法的重载:overload
在同一个类的内部,方法名字相同,参数列表不同,与返回类型无关的方法。
方法的重写:override overwrite 覆盖
前提条件:存在继承。在子类中重写父类的方法。
为什么需要重写:子类对象觉得父类中继承的方法不能满足自身的需求了。需要重新定义该方法。就可以在子类中对父类中的被继承的下来的方法进行重写。
如何重写:[权限修饰符] 返回类型 方法名字(参数列表)...(抛出异常)...{方法体}
1:权限修饰符:子类必须比父类更加的无私。
子类重写父类的方法,子类中的方法被访问权限必须要大于等于父类的。
2:返回类型:
如果是基本数据类型,那么必须一致。
如果是引用数据类型,那么子类中的方法的返回类型可以是父类的返回类型的子类型。
3:方法名字:必须一致。
4:参数列表:必须一致。不一致就是重载。
5: 方法抛出的异常类型列表:方法执行的时候可能引发的问题。 子类引发的问题必须小于等于父类的。子类抛出的异常类型必须小于等于父类的。
6:方法体:不一致。
注意:静态方式是否可以重写?
不能重写。静态的方法可以被子类继承,不能被子类重写。
五、super:
作用:
1:在子类中访问父类的被继承的成员。当子类和父类的成员存在语义上的冲突的时候,需要用super.来定位访问的父类的成员。
2:在子类中的构造方法的第一句,来调用父类的构造方法.
解释:在调用子类的构造方法的时候,父类的构造方法会优先执行,然后在执行子类的构造方法。
这个功能是由super 来完成的。
注意:在每个子类的构造方法的第一句,都必须显式的或者隐式的通过super 调用父类的构造方法。
隐式调用只能是调用父类的默认的无参的构造方法。super();
如果一个父类没有默认无参的构造方法。那么必须使用super显式调用父类的构造方法。
通过这样的语言机制,保证了父类的构造方法先执行完毕,然后再执行子类的构造方法的内容。
通过super 来访问父类的构造方法。执行父类构造方法的意义在于:对父类实例成员进行初始化。
通过在子类构造方法第一句使用super 调用父类的构造方法。
this 调用构造方法也是第一句。两句代码不冲突,因为 this 调用的构造方法的第一句 就是调用的super();有了this 调用构造方法就不能再有super 调用父类的构造方法。
六、生成子类对象的过程:
类中包含的内容:成员变量、成员方法、构造方法、构造块、静态块。
//生成一个子类对象的时候,那么父类中的静态块,构造块,构造方法,以及子类中的静态块,构造块,构造方法的一个执行的顺序。
1:先执行父类的静态代码块,然后是子类的静态代码块。
先加载父类,然后再加载子类。
2:父类的构造块,父类 的构造方法
父类的实例成员进行初始化。
3:子类的构造块,子类的构造方法。
子类的实例成员进行初始化。
生成子类对象的过程描述:
1:类加载
按照整个子类的继承的体系,从上到下从最上层的父类,到最底层的子类,进行类加载。
进行父类加载:对父类的静态成员初始化。执行父类的静态块。
最后加载子类:对子类中的静态成员进行初始化,执行子类的静态块。
2:先对最上层的父类的实例成员进行空间的分配,默认初始化,声明处的赋值,构造块,构造方法。
3:中间可能有多个继承的层次,从上到下都进行 [如上] 的执行的步骤。
4:最后对子类的实例成员进行空间的分配,默认初始化,声明赋值,构造块。构造方法。
七、toString方法
public String toString():返回该对象的字符串表示。
通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:
getClass().getName() + '@' + Integer.toHexString(hashCode())
返回:该对象的字符串表示形式。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
getClass().getName():得到当前对象的包名+类名的字符串表示形式。
Integer.toHexString(hashCode()):得到当前对象的内存地址并转换为16进制形式的字符串。
import com.bjsxt.util.MyUtil;
public class TestToString {
public static void main(String[] args) {
Girl girl = new Girl(17, MyUtil.getRandomNumber(60, 121), "婷婷");
//底层girl 调用 toString 方法。如果子类没有重写toString 那么将调用父类Object 的toString 方法。
//如果想得到自定义的对象的字符串表示形式,那么需要重写toString 方法。
System.out.println(girl);
}
}
class Girl{
private int age;
private int iq;//[60~120]
private String name;
Girl(int age, int iq, String name) {
super();
this.age = age;
this.iq = iq;
this.name = name;
}
@Override
public String toString() {
return "Girl [age=" + age + ", iq=" + iq + ", name=" + name + "]";
}
}
八、instanceof
instanceof:java 的一个运算符 ,一个关键字。
作用:判断某个对象是否是某种类型的实例。
语法形式:对象instanceof 类型
返回值:boolean值,如果 左边的对象是右边类型的实例。那么返回 true ,否则返回 false。
结论:子类对象永远是父类类型的实例。父类对象不是子类类型的实例。
注意:左边对象的类型必须和右边类型存在继承关系才可以使用instanceof 进行判断。
/**
* 定义一个父类:Shape 形状 属性,面积 s,周长 length。 重写Object toString 方法。 定义两个方法,一个求面积,一个求周长。 return 0 就是为了被覆盖的。
* 矩形,width ,height, 重写 父类的求面积 ,和周长的方法。构造方法,2个 有参 和 无参。对成员变量提供访问器和修改器。 getter setter。
* 圆,继承 Shape。 半径 radius。 重写父类的求面积和周长的方法。 构造方法,2个 有参 和 无参。对成员变量提供访问器和修改器。 getter setter。
* 定义测试类,生成一个矩形的对象,调用有参的构造方法。 求该矩形的面积和周长。 最后调用toString 方法即可。
* 同样生成一个圆的对象。 面积周长。toString Round Circle Rectangle
*
*/
public class TestShape {
public static void main(String[] args) {
Rectangle rect = new Rectangle(10, 10);
rect.getArea();
rect.getLength();
System.out.println(rect);
Round round = new Round(10);
round.getArea();
round.getLength();
System.out.println(round);
System.out.println(rect instanceof Rectangle);//true
System.out.println(round instanceof Round);//true
System.out.println(rect instanceof Shape);//true
System.out.println(new Shape() instanceof Rectangle);//false
System.out.println(rect instanceof Object);//true
}
}
class Shape{
//形状的面积
private double area;
//形状的周长
private double length;
public double getArea(){
return 0;
}
public double getLength(){
return 0;
}
public void setArea(double area) {
this.area = area;
}
public void setLength(double length) {
this.length = length;
}
@Override//重写检测 后面的方法必须是重写父类的方法,不是重写就编译错误。
public String toString() {
return "Shape [area=" + area + ", length=" + length + "]";
}
}
class Rectangle extends Shape{
private int width;
private int height;
public Rectangle() {
}
public Rectangle(int width, int height) {
super();
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public double getArea() {
//计算面积,并将面积的结果赋值给父类的面积变量
int area = width * height;
setArea(area);
return area;
}
@Override
public double getLength() {
int length = width + height << 1;
setLength(length);
return length;
}
}
//圆,继承 Shape。 半径 radius。 重写父类的求面积和周长的方法。 构造方法,2个 有参 和 无参。对成员变量提供访问器和修改器。 getter setter。
class Round extends Shape{
private int radius;
public Round() {
}
Round(int radius) {
super();
this.radius = radius;
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public double getLength() {
double length = 2 * Math.PI * radius;
setLength(length);
return length;
}
@Override
public double getArea() {
double area = Math.PI * radius * radius;
setArea(area);
return area;
}
}