一、继承性
|-好处:
①减少了代码的冗余,提高了代码的复用性
②便于功能的扩展
二、继承性的格式:
class A extends B{}
A: 子类、派生类、subclass
B:父类、超类、基类
①体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性、方法
②特别的:父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已
③子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的扩展,子类和父类的关系不同于子集和集合的关系
三、Java中关于继承性的规定
①一个类可以被多个子类继承
②Java中类的单继承性:一个类只能有一个父类
③子父类是相对的概念
④子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
⑤子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
四、Object类的理解
①如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
②所有的java类(除 java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
③所有的java类具有java.lang.Object类声明的功能
例一:
package com.atguigu.exer;
public class ManKind {
private int sex;
private int salary;
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manOrWoman() {
if (sex == 1) {
System.out.println("man");
} else if (sex == 0) {
System.out.println("woman");
}
}
public void employeed() {
String jobInfo = (salary == 0) ? "no job" : "job";
System.out.println(jobInfo);
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
package com.atguigu.exer;
public class Kids extends ManKind{
private int yeearOld;
public Kids() {
}
public Kids(int yeearOld) {
this.yeearOld = yeearOld;
}
public void printAge() {
System.out.println("I am " + yeearOld + "years old.");
}
public int getYeearOld() {
return yeearOld;
}
public void setYeearOld(int yeearOld) {
this.yeearOld = yeearOld;
}
}
package com.atguigu.exer;
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manOrWoman();
}
}
例二:
package com.atguigu.exer2;
public class Circle {
private double radius;// 半径
public Circle() {
radius = 1.0;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public Circle(double radius) {
this.radius = radius;
}
//返回圆的面积
public double findArea() {
return Math.PI * radius * radius;
}
}
package com.atguigu.exer2;
public class Cylinder extends Circle {
private double length;// 高
public Cylinder() {
length = 1.0;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
//返回圆柱的体积
public double findVolume() {
// return Math.PI*getRadius()*getRadius()*getLength();
return findArea() * getLength();
}
}
package com.atguigu.exer2;
public class CylinderTest {
public static void main(String[] args) {
Cylinder cy = new Cylinder();
cy.setRadius(2.1);
cy.setLength(3.4);
double volume = cy.findVolume();
System.out.println("圆柱的体积为:" + volume);
double area = cy.findArea();
System.out.println("底面圆的面积:" + area);
}
}
五、Debug的使用
①如何调试程序:
|-System.out.println().
|-Eclipse - Debug:
步骤:设置断点(可以设置多个断点)---- debug as java application
②Debug中step into 功能失灵的问题:
出现这个问题可能是以jre开头,所以将图片中箭头所指位置换为以jdk开头(这个文件为磁盘中jdk的安装位置)
六、方法的重写(override/overwrite)
①定义:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
②应用:重写以后,当创建子类对象以后,通过子类对象调用父类中的同名参数的方法时,实际执行的是子类重写父类的方法
③重写的规定:
方法的声明:权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
// 方法体
}
约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法
①子类重写的方法的方法名和形参列表与被重写的方法的方法名和形参列表相同
②子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
>特殊情况:子类中不能重写父类中声明为private权限的方法
③返回值类型:
>父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型是void
>父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
>父类被重写的方法的返回值类型是基本数据类型(比如double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
**************************************************************************************************************
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)
例一:
package com.atguigu.java1;
public class Person {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("吃饭!");
}
public void walk(int distance) {
System.out.println("走路,走的距离是:" + distance + "公里");
}
public Object infO() {
return null;
}
public double info1() {
return 1.0;
}
}
package com.atguigu.java1;
public class Student extends Person {
String major;
public Student() {
}
public Student(String major) {
this.major = major;
}
public void study() {
System.out.println("学习,专业是:" + major);
}
//对父类的eat方法进行了重写
public void eat() {
System.out.println("学生应该多吃有营养的食物!");
}
public String infO() {
return null;
}
// public int info1() {
// return 1;
// }
}
package com.atguigu.java1;
public class PersonTest {
public static void main(String[] args) {
Student s = new Student("计算机科学与技术");
s.eat();
s.walk(10);
s.study();
Person p1 = new Person();
p1.eat();
}
}
例二:
package com.atguigu.exer;
public class Kids extends ManKind{
private int yeearOld;
public Kids() {
}
public Kids(int yeearOld) {
this.yeearOld = yeearOld;
}
public void printAge() {
System.out.println("I am " + yeearOld + "years old.");
}
public int getYeearOld() {
return yeearOld;
}
public void setYeearOld(int yeearOld) {
this.yeearOld = yeearOld;
}
public void employeed() {
System.out.println("kids should study and no job");
}
}
package com.atguigu.exer;
public class ManKind {
private int sex;
private int salary;
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manOrWoman() {
if (sex == 1) {
System.out.println("man");
} else if (sex == 0) {
System.out.println("woman");
}
}
public void employeed() {
String jobInfo = (salary == 0) ? "no job" : "job";
System.out.println(jobInfo);
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
package com.atguigu.exer;
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manOrWoman();
}
}
例三:
package com.atguigu.exer2;
public class Circle {
private double radius;// 半径
public Circle() {
radius = 1.0;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public Circle(double radius) {
this.radius = radius;
}
//返回圆的面积
public double findArea() {
return Math.PI * radius * radius;
}
}
package com.atguigu.exer2;
public class Cylinder extends Circle {
private double length;// 高
public Cylinder() {
length = 1.0;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
//返回圆柱的体积
public double findVolume() {
return Math.PI * getRadius() * getRadius() * getLength();
// return findArea() * getLength();
}
public double findArea() {// 返回圆柱的表面积
return Math.PI * getRadius() * getRadius() * 2 + 2 * Math.PI * getRadius() * getLength();
}
}
package com.atguigu.exer2;
public class CylinderTest {
public static void main(String[] args) {
Cylinder cy = new Cylinder();
cy.setRadius(2.1);
cy.setLength(3.4);
double volume = cy.findVolume();
System.out.println("圆柱的体积为:" + volume);
//double area = cy.findArea();
//System.out.println("底面圆的面积:" + area);
double area = cy.findArea();
System.out.println("圆柱的表面积:" + area);
}
}
七、测试四种不同的权限修饰
①同一个包中的其他类,不可以调用Order类中私有的属性、方法
②在不同的子类中,不能调用Order类中声明为private和缺省权限的属性、方法
③不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法
例:
package com.atguigu.java2;
public class Order {
private int orderPrivate;
int orderDefault;
protected int orderProtected;
public int orderPublic;
private void methodPrivate() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
void methodDefault() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
protected void methodProtected() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
public void methodPublic() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
}
package com.atguigu.java2;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderDefault = 1;
order.orderProtected = 2;
order.orderPublic = 3;
order.methodDefault();
order.methodProtected();
order.methodPublic();
//同一个包中的其他类,不可以调用Order类中私有的属性、方法
// order.orderPrivate();
// order.methodPrivate();
}
}
package com.atguigu.java3;
import com.atguigu.java2.Order;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderPublic = 1;
order.methodPublic();
//不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法
// order.orderPrivate = 2;
// order.orderDefault = 3;
// order.orderProtrct = 4;
//
// order.methodPrivate();
// order.methodDefault();
// order.methodProtected();
//
}
public void show(Order order) {
order.orderPublic = 1;
order.methodPublic();
//不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法
// order.orderPrivate = 2;
// order.orderDefault = 3;
// order.orderProtrct = 4;
//
// order.methodPrivate();
// order.methodDefault();
// order.methodProtected();
//
}
}
package com.atguigu.java3;
import com.atguigu.java2.Order;
public class SubOrder extends Order {
public void method() {
orderProtected = 1;
orderPublic = 2;
methodProtected();
methodPublic();
//在不同的子类中,不能调用Order类中声明为private和缺省权限的属性、方法
// orderDefault = 3;
// orderPrivate = 4;
// methodDeafault();
// methodPrivate();
}
}
④super调用构造器:
|-可以在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器
|-“super(形参列表)”的使用,必须声明在子类构造器的首行
|-在类的构造器中,针对于“this(形参列表)”或“super(形参列表)”只能二选一,不能同时出现
|-在构造器的首行,没有显式的声明“this(形参列表)”或“super(形参列表)”,则默认调用的是父类中空参的构造器:super()
|-在类的多个构造器中,至少有一个类的构造器使用了super(形参列表)”,调用父类中的构造器
例:
package com.atguigu.java3;
public class Person {
String name;
int age;
int id = 1001;// 身份证号
public Person() {
System.out.println("我无处不在!");
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(name);
this.age = age;
}
public void eat() {
System.out.println("人吃饭!");
}
public void walk() {
System.out.println("人走路!");
}
}
package com.atguigu.java3;
public class Student extends Person {
String major;
int id = 1002;// 学号
public Student() {
super();
}
public Student(String major) {
super();
this.major = major;
}
public Student(String name, int age, String major) {
super(name, age);
this.major = major;
}
public void eat() {
System.out.println("学生多吃有营养的食物!");
}
public void Study() {
System.out.println("学生多学知识!");
this.eat();
super.eat();
super.walk();
}
public void show() {
System.out.println("name = " + this.name + ",age = " + super.age);
System.out.println("id = " + this.id);
System.out.println("id = " + super.id);
}
}
package com.atguigu.java3;
public class SuperTest {
public static void main(String[] args) {
Student s = new Student();
s.show();
System.out.println();
s.Study();
Student s1 = new Student("Tom", 21, "IT");
s1.show();
System.out.println("********************");
Student s2 = new Student();
}
}
八、子类对象实例化全过程
①从结构上来看:(继承性)
|-子类继承父类以后,就获取了父类中声明的属性或方法
|-创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
②从过程上看:
|-通过子类的构造器创建子类对象时,一定会直接或间接的调用其父类的构造器,进而调用父类的父类构造器........,直到调用了java.lang.Object 类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用
|-明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象
九、练习
例:
package com.atguigu.exer3;
public class Account {
private int id;// 账号
private double balance;// 余额
private double annualInterestRate;// 年利率
public Account(int id, double balance, double annualInterestRate) {
super();
this.id = id;
this.balance = balance;
this.annualInterestRate = annualInterestRate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnualInterestRate() {
return annualInterestRate;
}
public void setAnnualInterestRate(double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
// 返回月利率
public double getMonthlyInterest() {
return annualInterestRate / 12;
}
// 取钱
public void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
return;
}
System.out.println("余额不足!");
}
// 存钱
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
}
package com.atguigu.exer3;
public class AccountTest {
public static void main(String[] args) {
Account acctt = new Account(1122, 20000, 0.045);
acctt.withdraw(30000);
System.out.println("您的账户余额为:" + acctt.getBalance());
acctt.withdraw(2500);
System.out.println("您的账户余额为:" + acctt.getBalance());
acctt.deposit(3000);
System.out.println("您的账户余额为:" + acctt.getBalance());
System.out.println("月利率为:" + acctt.getMonthlyInterest() * 100 + "%");
}
}
package com.atguigu.exer3;
public class CheckAccount extends Account {
private double overdraft;// 可透支限额
public CheckAccount(int id, double balance, double annualInterestRate, double overdraft) {
super(id, balance, annualInterestRate);
this.overdraft = overdraft;
}
public double getOverdraft() {
return overdraft;
}
public void setOverdraft(double overdraft) {
this.overdraft = overdraft;
}
public void withdraw(double amount) {
if (getBalance() > amount) {// 余额足够消费
// 方式一:
// setBalance(getBalance()-amount);
super.withdraw(amount);
} else if (overdraft >= amount - getBalance()) {// 透支额度+余额足够消费
overdraft -= (amount - getBalance());
// setBalance(0);
super.withdraw(getBalance());
} else {
System.out.println("超过可透支限额!");
}
{
}
}
}
package com.atguigu.exer3;
public class CheckAccountTest {
public static void main(String[] args) {
CheckAccount acct = new CheckAccount(1122, 20000, 0.045, 5000);
acct.withdraw(5000);
System.out.println("您的账户余额为:" + acct.getBalance());
System.out.println("您的可透支余额为:" + acct.getOverdraft());
acct.withdraw(18000);
System.out.println("您的账户余额为:" + acct.getBalance());
System.out.println("您的可透支余额为:" + acct.getOverdraft());
acct.withdraw(3000);
System.out.println("您的账户余额为:" + acct.getBalance());
System.out.println("您的可透支余额为:" + acct.getOverdraft());
}
}
十、多态性的使用
①理解:可以理解为一个事物的多种形态
②何为多态性:
|-对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
|-当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法------虚拟方法调用
③多态的使用:虚拟方法调用
|-有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,实际执行的是子类重写父类的方法
|-总结:编译:看左边;运行:看右边
④多态性的使用前提:
|-类的继承关系
|-方法的重写
⑤对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
例一:
package com.atguigu.java4;
public class Person {
String name;
int age;
int id = 1001;
public void eat() {
System.out.println("吃饭!");
}
public void walk() {
System.out.println("走路!");
}
}
package com.atguigu.java4;
public class Man extends Person {
boolean isSmoking;
int id = 1002;
public void earnMoney() {
System.out.println("挣钱,养家!");
}
public void eat() {
System.out.println("多吃肉!");
}
public void walk() {
System.out.println("霸气的走路");
}
}
package com.atguigu.java4;
public class Woman extends Person {
boolean isBeauty;
public void goShopping() {
System.out.println("女人喜欢购物!");
}
public void eat() {
System.out.println("减肥!");
}
public void walk() {
System.out.println("窈窕的走路");
}
}
package com.atguigu.java4;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
Man man = new Man();
man.eat();
man.age = 25;
man.earnMoney();
//****************************************************
System.out.println("****************************");
//对象的多态性:父类的引用指向子类的对象
Person p2 = new Man();
//Person p3 = new Woman();
//多态的使用
p2.eat();
p2.walk();
//p2.earnMoney();
System.out.println(p2.id);
}
}
例二:
package com.atguigu.java4;
import java.sql.Connection;
//多态性的使用举例一:
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
test.func(new Dog());
test.func(new Cat());
}
public void func(Animal animal) {// Animal animal = new Dog();
animal.eat();
animal.shout();
}
// public void func(Dog dog){
// dog.eat();
// dog.shout();
// }
// public void func(Cat cat){
// cat.eat();
// cat.shout();
// }
}
class Animal {
public void eat() {
System.out.println("动物:进食");
}
public void shout() {
System.out.println("动物:叫");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃骨头");
}
public void shout() {
System.out.println("汪!汪!汪!");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
public void shout() {
System.out.println("喵!喵!喵!");
}
}
//举例二:
class Order {
public void method(Object obj) {
}
}
//举例三:
class Driver {
public void doData(Connection conn) {// conn = new MySQlConnection(); / conn = new OracleConnection();
// 规范的步骤去操作数据
// conn.method1();
// conn.method2();
// conn.method3();
}
}
⑥虚拟方法的调用:
|-正常的方法调用:
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
|-虚拟方法调用(多态情况下):
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法,这样的方法调用在编译期是无法确定的。
Person e = new Student();
e.getInfo();//调用Student类的getInfo()方法
|-编译时类型和运行时类型:
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。——动态绑定
|-方法的重载与重写:
①从编译和运行的角度看:
重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。
所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
②而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。
|-面试题:
多态是编译时行为还是运行时行为?证明如下:
package com.atguigu.java5;
import java.util.Random;
class Animal {
protected void eat() {
System.out.println("animal eat food");
}
}
class Cat extends Animal {
protected void eat() {
System.out.println("cat eat fish");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("Dog eat bone");
}
}
class Sheep extends Animal {
public void eat() {
System.out.println("Sheep eat grass");
}
}
public class InterviewTest {
public static Animal getInstance(int key) {
switch (key) {
case 0:
return new Cat();
case 1:
return new Dog();
default:
return new Sheep();
}
}
public static void main(String[] args) {
int key = new Random().nextInt(3);
System.out.println(key);
Animal animal = getInstance(key);
animal.eat();
}
}
十一、向下转型
|-使用强制类型转换符(向下转型)调用子类特有的属性和方法
|-使用强转时,可能出现ClassCastException的异常
|-instanceOf关键字的使用:
①a instanceOf A:判断对象a是否是类A的实例,如果是,返回true,如果不是返回false
②如果a instanceOf A返回true,则a instanceOf B也返回true,其中类B是类A的父类
使用情境:
为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceOf的判断,一旦返回true就进行向下转型,如果返回false,不进行向下转型
例:
package com.atguigu.java;
public class Person {
String name;
int age;
int id = 1001;
public void eat() {
System.out.println("吃饭!");
}
public void walk() {
System.out.println("走路!");
}
}
package com.atguigu.java;
public class Man extends Person {
boolean isSmoking;
int id = 1002;
public void earnMoney() {
System.out.println("挣钱,养家!");
}
public void eat() {
System.out.println("多吃肉!");
}
public void walk() {
System.out.println("霸气的走路");
}
}
package com.atguigu.java;
public class Woman extends Person {
boolean isBeauty;
public void goShopping() {
System.out.println("女人喜欢购物!");
}
public void eat() {
System.out.println("减肥!");
}
public void walk() {
System.out.println("窈窕的走路");
}
}
package com.atguigu.java;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
Man man = new Man();
man.eat();
man.age = 25;
man.earnMoney();
//****************************************************
System.out.println("****************************");
// 对象的多态性:父类的引用指向子类的对象
Person p2 = new Man();
// Person p3 = new Woman();
// 多态的使用
p2.eat();
p2.walk();
// p2.earnMoney();
System.out.println(p2.id);
System.out.println("******************************");
// 不能调用子类所特有的方法:编译时,p2是Person类型
// p2.earnMoney();
// p2.name = "Tom";
// p2.isSmoking = true;
/*
* 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型
* 导致编译时,只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用
*/
// 使用强制类型转换符调用子类特有的属性和方法(向下转型)
Man m1 = (Man) p2;
m1.earnMoney();
m1.isSmoking = true;
// 使用强转时,可能出现ClassCastException的异常
// Woman w1 = (Woman)p2;
// w1.goShopping();
if (p2 instanceof Woman) {
Woman w1 = (Woman) p2;
w1.goShopping();
System.out.println("*****Woman*******");
}
if (p2 instanceof Man) {
Man m2 = (Man) p2;
m2.earnMoney();
System.out.println("*****man*******");
}
if (p2 instanceof Person) {
System.out.println("*****Person********");
}
if (p2 instanceof Object) {
System.out.println("******Object********");
}
//问题一:编译通过,运行不通过:
// Person p3 = new Woman();
// Man m3= (Man)p3;
// Person p4 = new Person();
// Man m4 = (Man)p4;
// m4.earnMoney();
//问题二:编译通过,运行也通过
Object obj = new Woman();
Person p = (Person)obj;
//问题三:编译不通过:
//Man m5 = new Woman();
//String str = new Date();
Object o= new Date();
String str1 = (String)o;
}
}
|-练习:
调用属性和方法:
①若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右面
②对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边
例:
package com.atguigu.exer;
class Base {
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base {
int count = 20;
public void display() {
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);
s.display();
Base b = s;// 多态性
// ==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
System.out.println(b == s);
System.out.println(b.count);
b.display();
}
}
基本操作:
package com.atguigu.exer;
public class InstanceTest {
public static void main(String[] args) {
// 虚拟方法调用
InstanceTest test = new InstanceTest();
test.method(new Student());
}
public void method(Person e) {
String info = e.getInfo();
System.out.println(info);
if (e instanceof Graduate) {
System.out.println("a graduated student");
System.out.println("a student");
System.out.println("a person");
} else if (e instanceof Student) {
System.out.println("a student");
System.out.println("a person");
} else {
System.out.println("a person");
}
}
}
class Person {
protected String name = "person";
protected int age = 50;
public String getInfo() {
return "Name: " + name + "\n" + "age: " + age;
}
}
class Student extends Person {
protected String school = "pku";
public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school;
}
}
class Graduate extends Student {
public String major = "IT";
public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school + "\nmajor:" + major;
}
}
几何图形:
package com.atguigu.exer1;
public class GeometricObject {
protected String color;
protected double weight;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public GeometricObject(String color, double weight) {
super();
this.color = color;
this.weight = weight;
}
public double findArea() {
return 0.0;
}
}
package com.atguigu.exer1;
public class Circle extends GeometricObject {
private double radius;
public Circle(double radius, String color, double weight) {
super(color, weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea() {
return 3.14 * radius * radius;
}
}
package com.atguigu.exer1;
public class MyRectangle extends GeometricObject {
private double width;
private double height;
public MyRectangle(double width,double height,String color, double weight) {
super(color, weight);
this.width = width;
this.height = height;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double findArea() {
return width*height;
}
}
package com.atguigu.exer1;
public class GeometricTest {
public static void main(String[] args) {
GeometricTest test = new GeometricTest();
Circle c1 = new Circle(2.3, "white", 1.0);
test.displayGeometricObject(c1);
Circle c2 = new Circle(3.3, "black", 1.0);
test.displayGeometricObject(c2);
boolean isEquals = test.equalsArea(c1, c2);
System.out.println("c1和c2的面积是否相等:" + isEquals);
MyRectangle rect = new MyRectangle(2.1, 3.4, "red", 2.0);
test.displayGeometricObject(rect);
}
public void displayGeometricObject(GeometricObject o) {
System.out.println("面积为:" + o.findArea());
}
public boolean equalsArea(GeometricObject o1, GeometricObject o2) {
return o1.findArea() == o2.findArea();
}
}
重写方法:
package com.atguigu.exer;
//考察多态笔试题:
public class InterviewTest1 {
public static void main(String[] args) {
Base1 base = new Sub1();
base.add(1, 2, 3);
// Sub s = (Sub)base;
// s.add(1,2,3);
}
}
class Base1 {
public void add(int a, int... arr) {
System.out.println("base");
}
}
class Sub1 extends Base1 {
public void add(int a, int[] arr) {
System.out.println("sub_1");
}
// public void add(int a, int b, int c) {
// System.out.println("sub_2");
// }
}
十二、Object类的使用
①Object类是所有Java类的根父类
②如果在类的声明中未使用extends关键字指明其父类,则默认父类java.lang.Object类
③Object类中的功能(属性、方法)就具有通用性
④Object类只声明了一个空参的构造器
Object类中的主要结构:
例:
package com.atguigu.java1;
public class ObjectTest {
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.getClass().getSuperclass());
}
}
class Order {
}
Clone:
package com.atguigu.java1;
//Object类的clone()的使用
public class CloneTest {
public static void main(String[] args) {
Animal a1 = new Animal("花花");
try {
Animal a2 = (Animal) a1.clone();
System.out.println("原始对象:" + a1);
a2.setName("毛毛");
System.out.println("clone之后的对象:" + a2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
class Animal implements Cloneable{
private String name;
public Animal() {
super();
}
public Animal(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Animal [name=" + name + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
Finalize:
package com.atguigu.java1;
public class FinalizeTest {
public static void main(String[] args) {
Person p = new Person("Peter", 12);
System.out.println(p);
p = null;// 此时对象实体就是垃圾对象,等待被回收。但时间不确定。
System.gc();// 强制性释放空间
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
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;
}
// 子类重写此方法,可在释放对象前进行某些操作
@Override
protected void finalize() throws Throwable {
System.out.println("对象被释放--->" + this);
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
|-= =和equals()方法的区别:
①==运算符:
|-可以使用在基本数据类型变量和引用数据类型变量中
|-如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等(不一定类型要相同)
|-如果比较的是引用数据类型变量:比较两个对象的地址值是否相等,即两个引用是否指向同一个对象实体
②equals()方法:
|-是一个方法,而非运算符
|-只适用于引用数据类型
|-Object类中equals()的定义:
public boolean equals(Object obj) {
return (this == obj);
}
说明:Object类中定义的equals()和==的作用是相同的:比较
|-String、Date、File包装类等都重写了Object类中的equals()方法,比较的不是两个引用的地址是否相同,而是比较两个对象的实体内容是否相同
|-重写equals():
①使用equals()通常是比较两个对象的“实体内容”是否相同,所以就需要对Object类中的equals()进行重写
② 重写的原则:比较两个对象的实体内容是否相同
例:
package com.atguigu.java1;
public class Customer {
private String name;
private int age;
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 Customer(String name, int age) {
super();
this.name = name;
this.age = age;
}
//自动生成:
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Customer other = (Customer) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
// 重写的原则:比较两个对象的实体内容(即:name和age)是否相同
//手动实现equals()重写:
// public boolean equals(Object obj) {
// System.out.println("Customer equals()....");
// if (this == obj) {
// return true;
// }
// if (obj instanceof Customer) {
// Customer cust = (Customer) obj;
// // 比较两个对象的每个属性是否都相同
// if (this.age == cust.age && this.name.equals(cust.name)) {
// return true;
// } else {
// return false;
// }
// // 或
// return this.age == cust.age && this.name.equals(cust.name);
// } else {
// return false;
// }
}
package com.atguigu.java1;
import java.util.Date;
public class EqualsTest {
public static void main(String[] args) {
//基本数据类型:
int i = 10;
int j = 10;
double d = 10.0;
System.out.println(i == j);
System.out.println(i == d);
boolean b = true;
// System.out.println(i == b);
char c = 10;
System.out.println(i == c);
char c1 = 'A';
char c2 = 65;
System.out.println(c1 == c2);
//引用数据类型:
Customer cust1 = new Customer("Tom", 21);
Customer cust2 = new Customer("Tom", 21);
System.out.println(cust1 == cust2);
String str1 = new String("atguigu");
String str2 = new String("atguigu");
System.out.println(str1 == str2);
System.out.println("******************");
System.out.println(cust1.equals(cust2));
System.out.println(str1.equals(str2));
Date date1 = new Date(32432525324L);
Date date2 = new Date(32432525324L);
System.out.println(date1.equals(date2));
}
}
==和equals()的区别:
①==既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址
②equals的话,它是属于java.lang.Objec里面的方法,如果该方法没有被重写过默认也是==;我们可以看到Stri叩等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。
③具体要看自定义类里有没有重写Object的equals方法来判断。
④通常情况下,重写equals方法,会比较类中的相应属性是否都相等。
重写equals()方法的原则:
① 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
② 自反性:x.equals(x)必须返回是“true”。
③传递性:如果x.equals(y)返回是“ true”,而且y.equals(z)返回是“ true”,那么z.equals(x)也应该返回是“true”。
④一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
⑤任何情况下,x.equals(null),永远返回是 “false”;x.equals(和x不同类型的对象)永远返回是“false”。
练习:
例一:
package com.atguigu.exer2;
public class OrderTest {
public static void main(String[] args) {
Order order1 = new Order(1001, "AA");
Order order2 = new Order(1001, "BB");
System.out.println(order1.equals(order2));
Order order3 = new Order(1001, "BB");
System.out.println(order2.equals(order3));
}
}
class Order {
private int orderId;
private String orderName;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Order(int orderId, String orderName) {
super();
this.orderId = orderId;
this.orderName = orderName;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Order) {
Order order = (Order) obj;
return this.orderId == order.orderId && this.orderName.equals(order.orderName);
}
return false;
}
}
例二:
package com.atguigu.exer2;
public class MyDateTest {
public static void main(String[] args) {
MyDate m1 = new MyDate(14, 3, 1976);
MyDate m2 = new MyDate(14, 3, 1976);
if (m1 == m2) {
System.out.println("m1==m2");
} else {
System.out.println("m1!=m2"); // m1 != m2
}
if (m1.equals(m2)) {
System.out.println("m1 is equal to m2");// m1 is equal to m2
} else {
System.out.println("m1 is not equal to m2");
}
}
}
class MyDate {
private int day;
private int month;
private int year;
public MyDate(int day, int month, int year) {
super();
this.day = day;
this.month = month;
this.year = year;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof MyDate) {
MyDate myDate = (MyDate) obj;
return this.day == myDate.day && this.month == myDate.month && this.year == myDate.year;
}
return false;
}
}
|-toString()的使用:
①当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
②Object类中toString的定义:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
③像String、Date、File、包装类等都重写了Object类中的toString()方法,使得在调用对象的toString()时,返回实体内容信息
④自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”
|-重写toString:
public String toString() {
return "Customer[name" + name + ",age =" + age + "]";
}
例:
package com.atguigu.exer3;
public class GeometricObject {
protected String color;
protected double weight;
public GeometricObject() {
super();
this.color = "white";
this.weight = 1.0;
}
public GeometricObject(String color, double weight) {
super();
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
package com.atguigu.exer3;
public class Circle extends GeometricObject {
private double radius;
public Circle() {
super();
radius = 1.0;
}
public Circle(double radius) {
super();
this.radius = radius;
}
public Circle(double radius, String color, double weight) {
super(color, weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
//求圆的面积
public double findArea() {
return 3.14 * radius * radius;
}
//比较两个圆的半径是否相等,如相等,返回true。
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Circle) {
Circle c = (Circle) obj;
return this.radius == c.radius;
}
return false;
}
public String toString() {
return "Circle [radius=" + radius + "]";
}
}
package com.atguigu.exer3;
public class CircleTest {
public static void main(String[] args) {
Circle circle1 = new Circle(2.3);
Circle circle2 = new Circle(3.3, "white", 2.0);
System.out.println("颜色是否相等:" + circle1.getColor().equals(circle2.getColor()));
System.out.println("半径是否相等:" + circle1.equals(circle2));
System.out.println(circle1);
System.out.println(circle2.toString());
}
}
十三、包装类的使用
|-单元测试方法的使用:
步骤:
①选中当前工程-----右键选择build path------add libraries-------JUnit4-------下一步
②创建Java类:进行单元测试
此时的Java类的要求:
1.此类是public的
2.此类提供公共的无参构造器
③此类中声明单元测试方法:
此时的单元测试方法要求:方法的权限是public,没有返回值类型,没有形参
④此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;
⑤声明好单元测试方法以后,就可以在方法体内测试相关的代码
⑥写完代码以后,左键双击方法名,右键:run as - JUnit Test
说明:如果执行结果没有任何异常:绿条;如果执行结果出现异常:红条
例:
package com.atguigu.java2;
import java.util.Date;
import org.junit.Test;
public class JUnitTest {
int num = 10;
@Test
public void TestEquals() {
String s1 = "MM";
String s2 = "MM";
System.out.println(s1.equals(s2));
// Object obj = new String("GG");
// Date date = (Date)obj;
System.out.println(num);
show();
}
public void show() {
num = 20;
System.out.println("show()....");
}
@Test
public void testtoString() {
String s2 = "MM";
System.out.println(s2.toString());
}
}
十四、包装类的理解
|-针对八种基本数据类型定义相应的引用类型—包装类(封装类)
|-包装类转化:
|-包装类的使用:
①Java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
例:
package com.atguigu.java2;
import java.lang.reflect.Method;
import org.junit.Test;
public class WrapperTest {
//String类型转换为基本数据类型、包装类:调用包装类的parseXxx(String s)
@Test
public void test5() {
String str1 = "123";
// 可能会报NumberFormatException
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1);
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
// 基本数据类型、包装类----->String类型:调用String重载的valueOf(Xxx xxx)
@Test
public void test4() {
int num1 = 10;
// 方式一:连接运算
String str1 = num1 + "";
// 方式二:调用String的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);
Double d1 = new Double(12.4);
String str3 = String.valueOf(d1);
System.out.println(str2);
System.out.println(str3);
}
// 包装类转换为基本数据类型:调用包装类的xxxValue()
@Test
public void test3() {
// int num1 = 10;
// //基本数据类型转化为包装类的对象
// method(num1);
// 自动装箱:
int num2 = 10;
Integer in1 = num2;// 自动装箱
boolean b1 = true;
Boolean b2 = b1;// 自动装箱
// 自动拆箱:包装类转换为基本数据类型
System.out.println(in1.toString());
int num3 = in1;// 自动拆箱
}
public void method(Object obj) {
System.out.println(obj);
}
// 包装类转换为基本数据类型:调用包装类的xxxValue()
@Test
public void test2() {
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1 + 1);
Float f1 = new Float(12.3);
float f2 = f1.floatValue();
System.out.println(f2 + f1);
}
// 基本数据类型转换为包装类:调用包装类的构造器
@Test
public void test1() {
int num1 = 10;
// System.out.println(num1.toString());
Integer in1 = new Integer(num1);
System.out.println(in1.toString());
Integer in2 = new Integer("123");
System.out.println(in2.toString());
// 报错
// Integer in3 = new Integer("123abc");
// System.out.println(in3.toString());
Float f1 = new Float(12.3F);
Float f2 = new Float("12.3");
System.out.println(f1);
System.out.println(f2);
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("TrUe");
System.out.println(b2);
Boolean b3 = new Boolean("true123");
System.out.println(b3);
Order order = new Order();
System.out.println(order.isMale);
System.out.println(order.isFemale);
}
}
class Order {
boolean isMale;
Boolean isFemale;
}
|-面试题:
package com.atguigu.java2;
import org.junit.Test;
public class InterviewTest {
@Test
public void test1() {
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);// 1.0
}
@Test
public void test2() {
Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);// 1
}
@Test
public void test3() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);// false
// Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],
// 保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在
// -128~127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率
Integer m = 1;
Integer n = 1;
System.out.println(m == n);// true
Integer x = 128;// 相当于new了一个Integer对象
Integer y = 128;// 相当于new了一个Integer对象
System.out.println(x == y);// false
}
}
练习:
package com.atguigu.exer4;
import java.util.Scanner;
import java.util.Vector;
import java.util.logging.Level;
public class ScoreTest {
public static void main(String[] args) {
// 1.实例化Scanner,用于从键盘获取学生成绩
Scanner scan = new Scanner(System.in);
// 2.创建Vector对象:Vector v=new Vector();相当于原来的数组
Vector v = new Vector();
// 3.通过for(;;)或while(true)方式,给Vector中添加数组
int maxScore = 0;
for (;;) {
System.out.println("请输入学生成绩(以负数代表输入结束):");
int score = scan.nextInt();
// 3.2 当输入是负数时,跳出循环
if (score < 0) {
break;
}
if (score > 100) {
System.out.println("输入的数据非法,请重新输入");
continue;
}
// 3.1 添加操作::v.addElement(Object obj)
// jdk5.0之前:
// Integer inScore = new Integer(score);
// v.addElement(inScore);//多态
// jdk5.0之后:
v.addElement(score);// 自动装箱
// 4.获取学生成绩的最大值
if (maxScore < score) {
maxScore = score;
}
}
// 5.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个学生的等级。
char level;
for (int i = 0; i < v.size(); i++) {
Object obj = v.elementAt(i);
// jdk 5.0之前:
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
// jdk 5.0之后:
int score = (int) obj;
if (maxScore - score <= 10) {
level = 'A';
} else if (maxScore - score <= 20) {
level = 'B';
} else if (maxScore - score <= 30) {
level = 'C';
} else {
level = 'D';
}
System.out.println("student-" + i + " score is " + score + ",level is " + level);
}
}
}