一:面向对象的第二个特征:继承,关键字extends
1.继承的好处:
1)减少代码的冗余,提高代码的复用性。
2)便于功能的扩展
3)为之后多态性的使用,提供了前提
2.继承性的格式:
class A extends B{}
A:子类,派生类、subclass
B:父类、超类、基类、superclass
3.子类继承父类后有哪些同?
体现:一旦子类A继承父类B后,子类A中就获得了父类B中声明的所有属性和方法。
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获得了父类的中的结构。只因为封装性的影响,使得子类不能直接调用父类的结构而已。
4.java中继承性的说明:
1)一个类可以被多个子类继承
2)java 中类的单继承性:一个类只能有一个父类
3)子父类是相对的概念
4)子类直接继承的父类,称为直接父类,间接继承的父类称为间接父类
5)子类继承父类后,就获得了直接父类以及所有间接父类中声明的属性和方法
6)如果一个类没有显示的声明一个类的父类的话,则此类继承于java.lang.object类
例题:基础账户和信用账户
class BaseAccount{
private double balance;
private int id;
private double interestrate;
public BaseAccount(){}
public BaseAccount(double balance, int id, double interestrate) {
super();
this.balance = balance;
this.id = id;
this.interestrate = interestrate;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance=balance;
}
public void overdraw(double balance) {
this.balance = balance;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getInterestrate() {
return interestrate;
}
public void setInterestrate(double interestrate) {
this.interestrate = interestrate;
}
//存钱
public void depsoite(double acct) {
if(acct>0) {
balance+=acct;
System.out.println("存钱成功"+balance);
}
else {
System.out.println("金额错误,存钱失败");
}
}
//取钱
public void withdraw(double acct) {
if(acct>balance) {
System.out.println("余额不足");
}else {
balance-=acct;
System.out.println("取钱成功"+acct);
}
}
}
class CreditAccount extends BaseAccount{
private double overdraw;
public CreditAccount() {
}
public CreditAccount(double balance, int id, double interestrate,double overdraw) {
super(balance, id, interestrate);
this.overdraw=overdraw;
}
public double getOverdraw() {
return overdraw;
}
public void setOverdraw(double overdraw) {
this.overdraw = overdraw;
}
public void withdraw(double acct) {
if(acct<getBalance()) {
//方式1:
//setBalance(getBalance()-acct);
//方式2:
super.withdraw(acct);
}
else if (overdraw>=acct-getBalance()) {
overdraw-=acct-getBalance();
//方式1:
//setBalance(0);
//方式2:
super.withdraw(getBalance());
}
else {
System.out.println("超过透支余额");
}
}
}
public class TestExtends {
public static void main(String []args) {
CreditAccount ca= new CreditAccount(2000, 1102, 0.45, 5000);
ca.withdraw(1000);
System.out.println("账户余额为:"+ca.getBalance());
System.out.println("透支余额为:"+ca.getOverdraw());
ca.withdraw(2000);
System.out.println("账户余额为:"+ca.getBalance());
System.out.println("透支余额为:"+ca.getOverdraw());
ca.withdraw(5000);
System.out.println("账户余额为:"+ca.getBalance());
System.out.println("透支余额为:"+ca.getOverdraw());
}
}
二:eclipse 的debug功能
1.如何调试程序:
1)打印输出语句:System.out.println()
2)eclipse -debug
步骤一: 打断点:点击代码行左侧,点击点的标识
步骤二:run as dubug 进入调式模式, 右侧显示加载在内存中的变量, 工具栏中两个图标:step over 逐行 , step into 进入 具体的结构
三:方法的重写 override/overwrite
1:子类继承父类后,可以对父类中同名同参数的方法 进行覆盖操作
2:应用:重写以后,当创建子类对象后,通过子类对象调用子父类中同名同参数方法时,实际执行的是子类重写父类的方法。
3:重写的规定:
方法的声明:权限修饰符 返回值类型 方法名(形参列表){
//方法体
}
约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法
1)子类重写的方法名和形参列表与父类被重写的方法名和形参列表相同
2)子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符,特殊情况,子类不能重写父类声明为private权限的方法
3)返回值类型:
》父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
》父类被重写的方法返回值类型是A类型,则子类重写的方法返回值类型可以是A类或A类的子类
》父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型
》子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
》子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static(不是重写)
例:person类和student类:
//person 类
class Person{
private String name;
private int age;
public Person() {
super();
}
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;
}
public void eat() {
System.out.println("人会吃饭!");
}
public void sleep() {
System.out.println("人会睡觉!");
}
}
class Student extends Person{
private String major;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age,String major) {
super(name, age);
// TODO Auto-generated constructor stub
this.major=major;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
//方法的重写
public void eat() {
System.out.println("学生要吃有营养的食物");
}
public void study()
{
System.out.println("学生要学习专业课程"+major);
}
}
//测试
public class TestPerson {
public static void main(String[] args) {
Student stu =new Student("tom",20,"it");
//调用子类覆写的方法
stu.eat();
//调用继承父类的方法
stu.sleep();
//调用子类独有的方法
stu.study();
}
}
四:关键字:super
super关键字的使用:
1.super 理解为父类的
2.super 可以用来调用:属性、方法、构造器
3.super的使用
》我们可以在子类的方法或构造器中。通过super.属性或super.方法的方式,显示的调用父类中声明的属性或方法,但是,通常情况下,我们习惯省略"super."
》特殊情况,当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显示的使用super.属性,表明调用的是父类中声明的属性
》特殊情况下,当子类重写了父类的方法后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用super.方法,表明调用的是父类中被重写的方法
4.super调用构造器
》我们可以在子类的构造器中显示的使用super(形参列表)的方式,调用父类中声明的
指定的构造器
》ssuper(形参列表)的使用,必须声明在子类构造器的首行
》我们在类的构造器中,针对this(形参列表)和super(形参列表)只能二选一,不能同时出现
》在构造器的首行,没有显示的声明this(形参列表)或super(形参列表),则默认调用的是父类中的空参构造器
例:Circle类和Cylinder类:
//定义圆类
class Circle{
private double radius;
public Circle() {
super();
}
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea() {
return 3.14*getRadius()*getRadius();
}
}
//定义圆柱类
class Cylinder extends Circle{
private double length;//高
public Cylinder(double length) {
super();
this.length = length;
}
//返回圆柱的体积
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double findVolume() {
return findArea()*getLength();
}
}
public class TestCylinder {
public static void main(String []args) {
Circle c =new Circle(2.0);
System.out.println("圆的面积为:"+c.findArea());
Cylinder cy =new Cylinder(5);
cy.setRadius(3);
System.out.println("圆柱的体积为:"+cy.findVolume());
}
}
五:面向对象第三个特征:多态
1.理解多态性,可以理解为一个事务的多种形态
2.何为多态性:即父类的引用指向子类的对象(或子类的对象赋给父类的引用)
3.多态的使用,虚拟方法的调用
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,
我们实际执行的是子类重写父类的方法。
总结:编译看左边,运行看右边。
4.多态性的使用前提:@类的继承关系@方法的重写
5.对象的多态性,只适用于方法,不适应于属性
例题:人类和男人
class Human{
private String name;
private int age;
public Human() {
super();
}
public Human(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;
}
public void eat() {
System.out.println("人类要吃饭!");
}
public void sleep(){
System.out.println("人类要睡觉!");
}
}
class Man extends Human{
public void eat() {
System.out.println("男人吃的多,力气比较大!");
}
public void earnMoney() {
System.out.println("男人要赚钱养家!");
}
}
public class TestDuotai1 {
public static void main(String[] args) {
//多态: 父类的引用调用子类的对象
Human p = new Man();
//调用子类的重写的方法
p.eat();
//编译不通过,父类无该方法
//p.earnMoney();
}
}
6.向下转型和向上转型:
》向上转型:多态
》为什么使用向下转型?
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类类型,导致编译通时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。如何才能调用子类特有的属性和方法?使用向下转型
》如何实现向下转型?
使用强制类型转换符:()
》使用时的注意点
1.使用强转时,可以能出现ClassCastException的异常
2.为了避免在向下转型时出现ClassCastExcepton的异常,我们在向下转型之前,先进行 instanceof的判断,一旦返回true,就进行向下转型,如果返回false,不进行向下转型。
7. instanceof 的使用:
》instanceof的关键字使用:
a instanceof A :判断对象a是否是类A的实例。如果是,返回true,如果不是返回false
如果 a instanceof A返回true,则a instanceof B也返回true,其中类B是类A的父类
注:a所属的类必须与类A必须是子类和父类的关系,否则编译错误
例题:人类和男人和女人(人类和男人的代码在上个例题)
class Women extends Human{
public void eat() {
System.out.println("女人吃的少,力气小");
}
public void buy() {
System.out.println("女人喜欢逛街购物!");
}
public class TestDuotai1{
public static void main(String[] args) {
//多态: 父类的引用调用子类的对象
Human p = new Man();
//调用子类的重写的方法
p.eat();
//编译不通过,父类无该方法
//p.earnMoney();
// 报:java.lang.ClassCastException 异常
Women w =(Women)p;
}
改进代码:
if(p instanceof Women){
//向下转型
Women w= (Women)p;
p.buy();
}
8.谈谈你对多态性的理解(面试题)
》实现代码的通用性
》Object类中定义的public boolean equals(Object obj){}
》jdbc:使用java 程序操作(获取数据库连接,CRUD)数据库(Mysql,Oracle、DB2,SqlSever)
》抽象类、接口的使用肯定体现 了多态性。(抽象类,接口不能实现实例化)
六:java.lang.Object 类
1 Object类的说明:
》Object 类是所有java类的根父类
》如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object 类
》Object类中的功能(属性,方法)就具通用性
属性:无
方法:equals()/toString() / getClass()/ hashCode()/clone()/finalize()
wait()/notify()/ notifyAll()
》Object类只声明了一个空参的构造器
2 equals()方法:
》是一个方法,而非运算符
》只适用于引用数据类型
》Object类中equals()方法的定义:
public boolean equals(Object obj){
return (this==obj);}
说明:Object 类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
》像String 、Date 、File 、包装类等都重写了Object类中的equals()方法,重写以后,比较的不是两个引用的的地址是否相同,而是比较两个对象的“实体内容”是否相同
》通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同,那么我们就需要对object类中的equals()进行重写,
重写的原则:比较两个对象的实体内容是否相同
3 equlas ()重写:
》手工重写(User类,属性age和name)
public boolean equals(Object obj){
if(this==obj){
return true;
}else if (obj instanceof User){
User u= (User)obj;
return this.age==u.age&&this.name.equals(u.name);
}
return false;
}
}
》开发中怎么实现: 自动生成
4 回顾 ==运算符的使用:
》可以使用在基本数据类型变量和引用数据类型变量中
》如果比较的是基本数据类型变量:比较的两个变量保存的数据是否相等(不一定类型要相同)
》如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体(符号两边的变量类型一致)
5 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 "User[name="+name+",age="+age+"]";
}
七:java中的junit单元测试
步骤:
1.选中当前工程 -右键选择:build path-add libraries-Junit4-下一步
2.创建java类,进行单元测试
此时的java 类要求: 1)此类时public的,2)此类提供公共的无参构造器
3.此类中声明单元测试方法
此时的单元测试方法:方法的权限时public,没返回值,没形参
4.此单元测试方法上需要声明注解:@Test ,并在单元测试中导入:import org.junit.Test
5. 声明好单元测试方法后,就可以在方法体内测试相关代码
6.写完代码后,左键双击单元测试方法名,右键run as-Junit Test
说明:
1.如果 执行结构没有任何异常:绿条,执行出现异常:红条
例 单元测试 动物类和狗类
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("汪汪汪!!!");
}
public void sleep() {
System.out.println("狗要睡觉!!!");
}
}
class Cat extends Animal{
public void eat() {
System.out.println("猫在吃鱼");
}
public void shout() {
System.out.println("喵喵喵!!!");
}
public void sleep() {
System.out.println("猫要睡觉!!!");
}
}
//单元测试
import org.junit.Test;
public class TestJunitDuoTai {
public TestJunitDuoTai() {}
@Test
public void test1() {
Animal a = new Dog();
a.eat();
a.shout();
}
}
八:基本数据类型与包装类
1.为什么要有包装类(封装类)
》为了使基本数据类型的变量具有类的特征,引入包装类。
2.基本的数据类型与对应的包装类:
3.基本数据类型 、包装类、String 相互转换
》基本数据类型《》包装类:JDK5.0新特性:自动装箱与自动拆箱
》基本数类型、包装类--》String:调用String类的重载方法valueOf(Xxx xxx)
》String 类--》基本数类型、包装类:调用包装类的parseXxx(String s)
注:转换时可能会出现Numbermart (String.valueOf("abc"))
例:基本数据类型与String相互转换
@Test
public void test2() {
//自动装箱
Integer i =10;
Double d =20.0;
System.out.println(i);
System.out.println(d);
//自动拆卸
int s1= i;
double d1=d;
System.out.println(s1);
System.out.println(d1);
//基本数据类型转换为String
int n2=100;
String str1 = String.valueOf(n2);
System.out.println(str1);
//String 转换为基本数据类型
String str2 ="200.12";
double d2=Double.parseDouble(str2);
System.out.println(d2);
}