记录一下曾经学习java的过程-仅供个人参考
java学习-day03
继承
继承的概念
一个类继承另外一个类,被继承的类称之为父类、基类、超类,继承的类称之为子类、派生类。
继承的特征
public class F {
private String name;//只有同类中可以访问
public F() {
System.out.println("F is init...");
}
public void show(){
System.out.println("F is show...");
}
}
class S extends F{
public S() {
super(); //缺省的调用父类的无参构造函数
System.out.println("S is init...");
}
}
测试:
public class Test {
public static void main(String[] args) {
S s = new S();
s.show();
}
}
输出结果:
F is init...
S is init...
F is show...
1、子类继承父类将继承父类的所有属性和方法,私有的(private)不能直接访问。需要通过接口访问。
2、要想创建子类对象,必先创建父类对象
3、类的继承是单继承、一个类只能直接接触一个父类,可以间接继承多个父类
间接继承
supper
1.可以通过supper关键字调用父类的属性和方法
2.可以通过supper关键字调用父类的构造函数,只能在子类的构造函数中调用父类的构造函数,必须是在第一行
class F{
public F(){
System.out.println("F 1");
}
public F(int i){
System.out.println("F 2");
}
}
class S extends F{
public S(){
// 默认是调用父类的无参构造函数 supper();
super(10);
System.out.println("S 1");
}
public S(int i){
System.out.println("S 2");
}
}
public class Test {
public static void main(String[] args) {
new S(); // F 2 => S 1
new S(10); //F 1=> S 2
}
}
this和supper使用
继承的总结
- 子类继承父类,继承了父类的所有属性和方法(包含私有的),私有的不能直接访问;
- 一个类如果没有使用 extends,那么它将继承 Object 类, Object 类是所有类的父类,始祖类;
- 一个类可以继承多个类,但 java 中规定一个类只能直接继承一个类;可以间接继承;
- 子类具有扩展的功能,扩展子类特有的属性和方法;
- 继承大大提供了代码的重复利用性;
为什么要继承:
java通过继承的机制实现了解决代码冗余、提高了代码的复用性、提高了程序的扩展性
JDK的继承
Object类
所有的类都是Object类的子类,java中如果说没有显示的 继承一个类,那么这个类缺省的继承了Object类,Object类叫做始祖类
案例:
需求:
银行需要去保存用户的基本信息,银行对于用户有详细的分类:普通用户、VIP用户、大客户
分析:
普通用户:
属性:姓名、性别、出生年月、身份证、电话、账户
方法:存款、取款
VIP用户:
属性:姓名、性别、出生年月、身份证、电话、账户、房屋编码、行驶证编码
方法:存款、取款、贷款
大客户:
属性:姓名、性别、出生年月、身份证、电话、账户、纳税人识别码
方法:存款、取款、贷款、开承兑
完成代码:
使用一个Account类来表示用户的银行账号信息
public class Account {
private String code;
private String pwd;
private double money;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
使用一个BaseUser类表示普通用户
import java.util.Date;
public class BaseUser {
private String name;
private char sex;
private Date birth;
private String phone;
private Account account;
/**
* 存钱
* @param money
*/
public void saveMoney(double money) {
}
/**
* 取钱
* @return
*/
public Double receiveMoney() {
return 0.0D;
}
}
使用VIPUser表示 VIP用户的基本信息
import java.util.Date;
public class VipUser {
private String name;
private char sex;
private Date birth;
private String phone;
private Account account;
private String houseCode;
private String carCode;
/**
* 存钱
* @param money
*/
public void saveMoney(double money) {
}
/**
* 取钱
* @return
*/
public Double receiveMoney() {
return 0.0D;
}
/**
* 贷款
* @param money
* @return
*/
public Double loanMoney(double money){
return 0.0D;
}
}
使用BigUser表示大客户的信息
import java.util.Date;
public class BigUser {
private String name;
private char sex;
private Date birth;
private String phone;
private Account account;
private String taxpayerCode;//纳税人识别码
/**
* 存钱
* @param money
*/
public void saveMoney(double money) {
}
/**
* 取钱
* @return
*/
public Double receiveMoney() {
return 0.0D;
}
/**
* 贷款
* @param money
* @return
*/
public Double loanMoney(double money){
return 0.0D;
}
public Double bigMoney(double money){
return 0.0D;
}
}
从以上的代码我们可以看到冗余代码,用户的基本信息、存款和取款的操作都是冗余代码
存款和取款的操作
使用继承的思想来解决代码冗余的问题
继承关系结构
1.修改VipUser删除和BaseUser共有的代码,是的VipUser继承BaseUser
2.修改BigUser删除和BaseUser共有的代码,是的VipUser继承BaseUser
3.删除BigUser 和VipUser 的存款和取款方法,使用父类BaseUser的方法
4.在BaseUser中实现存款和取款的方法
/** * 存钱 * * @param money */
public void saveMoney(double money) {
//实现存款的业务
//用户账户的余额和存入的金额相加
double add = this.account.getMoney() + money;
//将得到的结果set到Account中
this.account.setMoney(add);
}
/**
* 取钱
*
* @return
*/
public Double receiveMoney(double money) {
//获取余额
double restMoney = account.getMoney();
//用余额- 取款的金额
restMoney = restMoney - money;
//判断余额是否<0 : 如果<0 则取款失败 返回用户取款0元 提示用户重新输入余额
if (restMoney < 0) {
System.out.println("余额不足,仅剩余额:" + (restMoney + money));
return 0.0D;
}
//重新设置余额
account.setMoney(restMoney);
return money;
}
5.实现基本用户的存款和取款业务 BaseTest
import java.util.Date;
public class BaseTest {
public static void main(String[] args) {
//功能1 存款
// 普通用户存款
BaseUser user = new BaseUser();
// 普通用户填写基本信息
user.setName("jack");
user.setSex('男');
Date date = new Date();//获取当前的日期
user.setBirth(date);
user.setPhone("18899998888");
//开户
Account account = new Account();//申请了一个内存空间
account.setCode("998");
account.setPwd("123456");
account.setMoney(1);
user.setAccount(account);
//存款
user.saveMoney(10000);
//确认用用户的余额
System.out.println(user.getName()+"的余额:"+user.getAccount().getMoney());
//取款
double money = user.receiveMoney(4000);
System.out.println(user.getName() + "取款:" + money);
System.out.println(user.getName()+"的余额:"+user.getAccount().getMoney());
}
}
6.实现VIP用户的存款和取款业务
import java.util.Date;
public class VipTest {
public static void main(String[] args) {
//VIP 用户存款
VipUser user = new VipUser();//申请了一个内存空间
//用户填写基本信息
user.setName("tom");
user.setSex('女');
Date date = new Date();//获取当前的日期
user.setBirth(date);
user.setPhone("18877887788");
//开户
Account account = new Account();//申请了一个内存空间
account.setCode("997");
account.setPwd("321321");
account.setMoney(1);
user.setAccount(account);
//存款
user.saveMoney(5000);
//确认余额
System.out.println(user.getName() + "的余额" + user.getAccount().getMoney());
//取款
double money = user.receiveMoney(6000);
System.out.println(user.getName() + "取款:" + money);
System.out.println(user.getName()+"的余额:"+user.getAccount().getMoney());
}
}
方法重写
概念
在子类继承父类的关系中,子类的方法名、参数列表、返回值类型全部相同,我们叫做方法重写(Override)
class F{
public void show(){
System.out.println("F is show");
}
}
class S extends F{
public void show(){
System.out.println("S is show");
}
}
public class Test {
public static void main(String[] args) {
S s = new S();
s.show();
}
}
通过方法重写优化银行业务的代码
1、在VipUser类中重写saveMoney、receiveMoney方法
2.测试接口
执行VipTest
说明调用了是子类的重写方法
抽象
抽象:就是抽取,抽取子类共有的属性和方法到父类。
抽象类是代码重构的结构,是抽象的。实际不存在的
抽象方法:只有方法的声明、没有方法的实现。
抽象类的特征:
1、抽象类是子类共有属性的方法抽象的结果,有abstract关键字来修饰
2、抽象类不能被实例化(new),抽象类有构造函数,而构造函数是用来被子类调用的
3、抽象类可以有实例方法、抽象方法、也可以没有
4、如果一个类继承了一个抽象类,那么这个类必须重写父类的所有抽象方法,包含间接继承。否则这个类也是一个抽象。抽象类可以不重写父类的抽象方法,也可以重写。
代码实现
abstract class F{
private String name;
public F() {
System.out.println("F is init");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("F is show");
}
//父类提供共有的方法接口 run 有子类来实现
public abstract void run();
}
class S extends F{
public S() {
super();
System.out.println("S is init");
}
@Override
public void run() {
System.out.println("S is run");
}
}
class D extends F{
public D() {
super();
System.out.println("D is init");
}
@Override
public void run() {
System.out.println("D is run");
}
}
public class Test {
public static void main(String[] args) {
S s = new S();
s.show();
s.run();
D d = new D();
d.show();
d.run();
}
}
运行结果
F is init
S is init
F is show
S is run
F is init
D is init
F is show
D is run
好好理解下面的代码:
abstract class A{
abstract void show();
}
abstract class B extends A{
abstract void run();
@Override
void show() {
}
}
abstract class C extends B{
}
class D extends B{
@Override
void run() {
}
}
public class Test {
}
里氏代换原则
当一个地方需要一个超类对象的时候,我们可以通过一个子类来代替它!
多态
什么是多态: 一种声明,多种实现!
编译时多态:体现为方法重载
在编译的时候已经决定了show方法有多种形参的可能性
运行时多态:体现为方法重写
f在运行的过程中,可以指向子类S的对象,也可以指向子类D 的对象
三大前提条件:
1、必须有继承
2、必须有重写
3、必须有父类的声明指向子类的引用
例子
案例1:方法重载的应用
案例2:方法重写
创建一个Persen抽象类
public abstract class Person {
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;
}
}
创建一个打印类Printer
/**
* 打印Person
*/
public class Printer {
/**
* 打印student和user的属性
*/
public void show(Person person){
//打印对象
System.out.println(person.getName()+"\t"+person.getAge());
}
}
创建Person 的子类User
public class User extends Person {
}
创建子类Student
public class Student extends Person {
}
测试
public class Test {
public static void main(String[] args) {
//多态是用于参数的传递
Printer f = new Printer();
Person person = new User();// 多态
person.setName("jack");
person.setAge(20);
f.show(person);//多态
person = new Student();
person.setName("小黑");
person.setAge(18);
f.show(person);
}
}
案例3:方法重写 - 工厂模式 - 简单工厂
对象抽象类:
public abstract class Person {
private String name;
private int age;
public Person() {
}
//提供给子类进行属性初始化用的
public Person(String name, int age) {
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;
}
}
打印类:打印Person的属性
/**
* 打印Person
*/
public class Printer {
/**
* 打印student和user的属性
*/
public void show(Person person){
//打印对象
System.out.println(person.getName()+"\t"+person.getAge());
}
}
工厂:根据用户的需求创建所需要的对象
/**
* 用来创建Person
*/
public class Factory {
public Person newInstance(String type,String name,int age){
switch (type){
case "U":
return new User(name,age);
case "S":
return new Student(name,age);
default:
return null;
}
}
}
业务类: 需要打印User的属性
public class User extends Person {
public User() {
}
public User(String name, int age) {
super(name, age);
}
}
需求增加:需要打印Student的属性
public class Student extends Person {
public Student() {
}
public Student(String name, int age) {
super(name, age);
}
}
测试:
Factory factory = new Factory();//帮助调用者取创建对应的对象
// 创建对象
Person person = factory.newInstance("U","jack",20);
Printer printer = new Printer();
printer.show(person);
工厂模式
工厂模式提高了程序的扩展性。
1、简单工厂
2、工厂方法
3、抽象工厂
需求:
我们需压设计一个汽车4S店的程序:卖奔驰、宝马 汽车可以行驶
step: 使用简单工厂实现 => test06
点评:使用简单工厂模式,我们实现Car解耦,如果需要增加一个比亚车车型的销售,只需要继承Car抽象类重写父类的方法,在工厂中增加比亚迪对象创建!从这个代码我们发现,新增一个成型,工厂类需要重新写是一种强耦合,不利于业务的扩展!
step:使用工厂方法来实现,我们仅需要改造工厂即可 => test07
点评:在实现了对汽车的扩展之外又实现了对工厂的抽象和拓展。新增一个品牌只要实现Car和AbstractFactory即可,生成一个新的4S点 XXXShop