Java基础编程 第四章 面向对象编程(上)2

  • 为什么需要封装?封装的作用和含义?
    • 我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
    • 我要开车。。。。
  • 我们程序设计追求”高内聚,低耦合“。
    • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
    • 低耦合:仅对外暴露少量的方法用于使用。
  • 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
/*
* 面向对象的特征之一:封装与隐藏
* 一、问题的引入:
*   当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到
*   属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值
*   加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如setLegs())
*   同时,我们需要避免用户再使用“对象.属性”的方式对属性进行赋值。则需要将属性声明为私有的(private)
*   >>>此时,针对于属性就体现了封闭性
* 二、封闭性的体现:
*   我们将类的属性xxx私有化(private),同时,提供公共(public)方法来获取(getXxx)和设置(setXxx)此的属性的值
*       拓展:封装性的体现:1)如上;2)不对外暴露的私有的方法;3)单例模式
* 三、封装性的体现,需要权限修饰符来配合。
*   1、Java规定的4种权限(从小到大):private、缺省、protected、public
*   2、4种权限可以用来修改类及类的内部结构:属性、方法、构造器、内部类
*   3、具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
*             修饰类的话:只能使用:缺省、public
* 总结封装性:Java提供了4种权限修饰符来修饰类的内部结构,体现类及类的内部结构在被调用的可见性的大小。
* */

public class AnimalTest {
    public static void main(String[] args) {
        Animal ani = new Animal();
        ani.name = "东东";
//        ani.age = 2;
//        ani.legs = 4;
        ani.setLegs(4);
        ani.setAge(2);
        ani.show();
        ani.eat();
    }
}

class Animal{
        String name;
       private int age;
       private int legs;//私有化
    //设置属性
    public void setLegs(int l) {
        if (l > 0 && l % 2 == 0 && l <= 8) {
            legs = l;
        } else {
            legs = 0;
            //抛出异常暂时没有讲
        }
    }
    //获取属性
    public int getLegs() {
        return legs;
    }

    public void eat() {
        System.out.println("我喜欢进食植物的嫩叶!");
    }

    public void show() {
        System.out.println("我的名字叫:" + name + ",我今年" + age + "岁了,我有" + legs + "条腿!");
    }

    //提供关于属性age的get和set方法
    public int getAge() {
        return age;
    }

    public void setAge(int a) {
        age = a;
    }
}

public class Person {
    private int age;

    public void setAge(int i) {
        if (i > 0 && i < 130) {
//            throw new RuntimeException("传入数据非法!");
            System.out.println("传入数据非法!");
            return;
        }
        age = i;
    }

    public int getAge() {
        return age;
    }
//      绝对不能这样写get与set方法
//    public int doAge(int a) {
//        age = a;
//        return age;
//    }
}

public class PersonTest {
    public static void main(String[] args) {
        Person b = new Person();
//        b.age = 10;//编译不通过
        b.getAge();
        b.setAge(10);
    }
}

/*
* 类的结构之三:构造器(或构造方法、constructor)的使用
* construct:建设、建造。construction:CCB    constructor:建设者
* 一、构造器的作用:
*   1、创建对象
*   2、初始化对象的信息
* 二、说明:
* 1、如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器
* 2、定义构造器的格式:权限修饰符 类名(形参列表){}
* 3、一个类中定义的多个构造器,彼此构成重载
* 4、一旦我们显式的定义了类的构造器之后,系统就不在提供默认的空参构造器
* 5、一类至少会有一个构造器。
* */
public class ConstructorTest {
    public static void main(String[] args) {
        //创建类的对象:new + 构造器
        Person p = new Person();
        p.eat();
        Person p2 = new Person("Tom");
        System.out.println(p2.name);
        Person p3 = new Person("jack",20);
        System.out.println(p3.name+"\t" + p3.age);

    }
}

class Person{
    //属性
    String name;
    int age;

    //构造器
    public Person(){
        System.out.println("默认的空参构造器......");
    }

    public Person(String n) {
        name = n;
    }

    public Person(String m, int a) {
        name = m;
        age = a;
    }

    //方法
    public void eat() {
        System.out.println("人吃饭");
    }
}

public class Person {
    private int age; 
    //练习9
    private String name;   
    public Person() {
        age = 18;
    }

    public Person(String n, int a) {
        name = n;
        age = a;
    }

    public void setName(String n) {
        name = n;
    }
    public String getName() {
        return name;
    }

    public void setAge(int i) {
        if (i > 0 && i < 130) {
//            throw new RuntimeException("传入数据非法!");
            System.out.println("传入数据非法!");
            return;
        }
        age = i;
    }

    public int getAge() {
        return age;
    }
//      绝对不能这样写get与set方法
//    public int doAge(int a) {
//        age = a;
//        return age;
//    }
}
public class PersonTest {
    public static void main(String[] args) {
        Person b = new Person();
//        b.age = 10;//编译不通过
        b.setAge(10);
        System.out.println("年龄为:" + b.getAge());
        Person p = new Person("tom",20);
        System.out.println("名字是:" + p.getName() + ",年龄为:" + p.getAge());
    }
}

练习 9  
3.编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。

public class TriAngle {
    private double base;
    private double height;
    //空参构造器
    public TriAngle() {

    }
    //有参构造器
    public TriAngle(double b,double h) {
        base = b;
        height = h;
    }
    public void setBase(double b) {
        base = b;
    }
    public double getBase() {
        return base;
    }

    public void setheight(double h) {
        height = h;
    }
    public double getheight() {
        return height;
    }
}
public class TriAngleTest {
    public static void main(String[] args) {
        TriAngle t = new TriAngle();
        t.setBase(3);
        t.setheight(5);
        System.out.println("三角形的底边长base为:" + t.getBase() + ",高height为:" + t.getheight());

        //计算三角形面积 = 1/2 * 底边长 * 高
        TriAngle t2 = new TriAngle(3.6, 2.5);
        System.out.println("三角形的底边长base为:" + t2.getBase() + ",高height为:" + t2.getheight());
        System.out.println("三角形的面积为:" + 0.5*t2.getBase()*t2.getheight());
    }
}

练习10

 (1)定义Student类,有4个属性:

String name;

int age;

String school;

String major;

(2)定义Student类的3个构造器:

第一个构造器Student(String n,int a)设置类的name和age属性;

第二个构造器Student(String n,int a,String s)设置类的name,age和school属性;

第二个构造器Student(String n,int a,String s,String m)设置类的name,age,school和major属性;

(3)在main方法中分别调用不同的构造器创建的对象,并输出其属性值。

public class StudentTest {
    public static void main(String[] args) {
        Student t1 = new Student("Tom", 18);
        System.out.println("构造器1:\t" + "name:" + t1.getName() + "\tage:" + t1.getAge());

        Student t2 = new Student("Lily", 18, "MIT");
        System.out.println("构造器2:\t" + "name:" + t2.getName() +
                "\tage:" + t2.getAge() + "\tschool:" + t2.getSchool());

        Student t3 = new Student("Jack", 18, "BNU", "PC");
        System.out.println("构造器3:\t" + "name:" + t3.getName() +
                "\tage:" + t3.getAge() + "\tschool:" + t3.getSchool() + "\tmajor:" + t3.getMajor());
    }
}
public class Student {
    String name;
    int age;
    String school;
    String major;

    public Student() {
    }
    public Student(String n,int a) {
        name = n;
        age = a;
    }
    public Student(String n,int a,String s) {
        name = n;
        age = a;
        school = s;
    }
    public Student(String n,int a,String s,String m) {
        name = n;
        age = a;
        school = s;
        major = m;
    }

    public void setName(String n) {
        name = n;
    }

    public String getName() {
        return name;
    }

    public void setAge(int a) {
        age = a;
    }

    public int getAge() {
        return age;
    }

    public void setSchool(String s) {
        school = s;
    }

    public String getSchool() {
        return school;
    }

    public void setMajor(String m) {
        major = m;
    }

    public String getMajor() {
        return major;
    }
}

总结:属性赋值过程

这几个位置,并指明赋值的先后顺序:

  • 赋值的位置:
    1. 默认初始化
    2. 显示初始化
    3. 构造器中初始化
    4. 通过“对象.属性”或“对象.方法”的方式赋值
  • 赋值的先后顺序:
    • 1 – 2 – 3 – 4

4.8 拓展知识:JavaBean

  • JavaBean是一种Java语言写成的可重用组件。
  • 所谓JavaBean,是批符合如下标准的Java类:
    • 类是公共的
    • 有一个无参的公共的构造器
    • 有属性,且有对应的get、set方法
  • 用户可以使用JavaBean将功能、处理、值、数据访问和其他任何可以用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。

4.8 拓展知识:UML类图


this是什么?

  • 在Java中,this关键字比较难理解,它的作用和其词义很接近。
    • 它在方法内部使用,即这个方法所属对象的引用;
    • 它在构造器内部使用,表示该构造器正在初始化对象。
  • this表示当前对象,可以调用类的属性、方法和构造器
  • 什么时候使用this关键字呢?
    • 当在方法内需要用到调用该方法的对象时,就用this。
    • 具体的:我们可以用this来区分局部变量和属性。
    • 比如:this.name = name;
/*
 * this 关键字的使用:
 * 1、this可以用来修饰或调用:属性、方法、构造器
 * 2、this修饰属性和方法:
 *   this理解为:当前对象 或 当前正在创建的对象
 *
 *     2.1在类的方法中,我们可以使用“this.属性”或“this.方法”的方式,调用当前对象属性或方法。
 * 通常情况下,我们都选择省略“this.”,特殊情况下,如果方法的形参和类的属性同名时,我们必须
 * 显式的使用“this.变量”的方式,表明此变量是属性,而非形参 。
 *    2.2在类的构造器中,我们可以使用“this.属性”或“this.方法”的方式,调用当前正在创建的属性或方法。
 * 通常情况下,我们都选择省略“this.”,特殊情况下,如果构造器的形参和类的属性同名时,我们必须
 * 显式的使用“this.变量”的方式,表明此变量是属性,而非形参 。
 *
 * 3、this调用构造器
 *    3.1我们在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中的其他构造器
 *    3.2构造器中不能通过“this(形参列表)”的方式调用自己
 *    3.3如果一类中有n 个构造器,则最多有n-1个构造器中使用“this(形参列表)”
 *    3.4规定:“this(形参列表)”必须声明在当前构造器的首行
 *    3.5构造器内部,最多只能声明一个“this(形参列表)”,用来调用其他的构造器。
 *
 * */
public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.setName("Ryan");
        p.setAge(7);

        Person p1 = new Person("Tom", 19);
        p1.setName("Wisnton");
        p1.setAge(20);

        System.out.println("name:" + p.getName() + "\tage:" + p.getAge());
        System.out.println("name:" + p1.getName() + "\tage:" + p1.getAge());
    }

    public static class Person {

        String name;
        int age;

        public Person() {
            this.eat();
        }

        public Person(int age) {
            this();
            //2.2
            this.age = age;
        }

        public Person(String name, int age) {
            //调用上面的Person()构造器
            this(age);
            this.name = name;
//            this.age = age;//调用上面构造器,已经有过这条,不再需要
        }


        public void eat() {
            System.out.println("人吃饭");
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            //2.1
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

public class BoyGirlTest {
    public static void main(String[] args) {
        Boy boy = new Boy("罗蜜欧",23);
        boy.shout();

        Girl girl = new Girl("朱丽叶",18);
        girl.marry(boy);

        Girl girl1 = new Girl("祝英台", 19);
        int compare = girl.compare(girl1);
        if (compare >= 1) {
            System.out.println(girl.getName() + "大");
        } else if (compare < 0) {
            System.out.println(girl1.getName() + "大");
        } else {
            System.out.println(girl.getName() + "和" + girl1.getName() + "一样大");
        }
    }
}
public class Boy {

    private String name;
    private int age;

    public Boy(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;
    }

    public void marry(Girl girl) {
        System.out.println("我想娶" + girl.getName());
    }
    public void shout() {
        if (this.age &gt; 22) {
            System.out.println("你可以给婚啦!");
        } else {
            System.out.println("快去谈恋爱吧!");
        }
    }
}
public class Girl {
    private String name;
    private int age;

    public Girl(String name,int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void marry(Boy boy) {
        System.out.println("我想嫁给" + boy.getName());
        boy.marry(this);
    }

    /*
    * 比较两个对象的大小
    * 正数:当前对象大;负数:当前对象小;0:当前对象与形参对象相等
    * */
    public int compare(Girl girl) {
        //方式一
//        if (this.age &gt; girl.age) {
//            return 1;
//        } else if (this.age &lt; girl.age) {
//            return -1;
//        } else {
//            return 0;
//        }
        //方式二
        return this.age - girl.age;
    }
}

练习 12

1、写一个名为Account的类模拟账户。该类的属性和方法如下图所示。该类包括的属性:账号id,余额balance,年利率annualInterestRate;包含的方法:访问器方法(getter和setter方法),取款方法withdraw(),存款方法deposit().

提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。

2、创建Customer类

  1. 声明三个私有对象属性:firstName、lastName和account。
  2. 声明一个仅有构造器,这个构造器带有两个代表对象属性的参数(f和l)
  3. 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。
  4. 声明setAccount方法来对account属性赋值。
  5. 声明getAccount方法以获取account属性。

3、写一个测试程序。

  1. 创建一个Customer,名字叫Jane Smith,他有一个账号为1000,余额为2000元,年利率为1.23%的账户。
  2. 对Jane Smith操作。
    • 存入100元,再取出960元。再取出2000元。
    • 打印出Jane Smith的基本信息

成功存入:100.00

成功取出:960.00

余额不足:取款失败

Customer [Smith,Jane] has a account: id is 1000, annualInterestRate is 1.23% ,banlance is 1140.0

public class CustomerTest {
    public static void main(String[] args) {
        Customer customer = new Customer("Jane", "Smith");
        Account account = new Account(1000, 2000, 0.0123);
        //给用户添加账号
        customer.setAccount(account);
        customer.getAccount().deposit(100);//存100
        customer.getAccount().withdraw(960);//取960
        customer.getAccount().withdraw(2000);//取2000
        System.out.println("Customer [" + customer.getLastName() + ","+customer.getFirstName()
                + "] has a account: id is " + customer.getAccount().getId() +", annualInterestRate is "
                + customer.getAccount().getAnnualInterestRate()*100 + "%, banlance is "
                +  customer.getAccount().getBalance());
    }
}
public class Account {
    private int id;//账号
    private double balance;//余额
    private double annualInterestRate;//年利率

    //初始化构造器
    public Account(int id, double balance, double annualInterestRate) {
        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 void withdraw(double amount) {//取钱
        if (amount < balance) {
            balance -= amount;
            System.out.println("成功取出:" + amount);
        } else {
            System.out.println("余额不足:取款失败");
        }
    }

    public void deposit(double amount) {//存钱
        if (amount > 0) {
            balance += amount;
            System.out.println("成功存入:" + amount);
        }
    }
}
public class Customer {
    private String firstName;
    private String lastName;
    private Account account;

    //初始化构造器
    public Customer(String f, String l) {
        this.firstName = f;
        this.lastName = l;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }
}

练习13

1、按照如下的UML类图,创建相应的类,提供必要的结构

在提款方法withdraw()中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。deposit()方法表示存款。

2、按照如下的UML类图,创建相应的类,提供必要的结构

3、按照如下的UML类图,创建相应的类,提供必要的结构

  • addCustomer方法必须依照参数(姓,名)构造一个新的Customer对象,然后把它放到customer数组中。还必须把numberofCustomer属性的值加 1。
  • getNumOfCustomers方法返回numberOfCustomer属性值。
  • getCustomer方法返回与给出的index参数相关的客户。

4、创建BankTest类,进行测试。

public class BankTest {
    public static void main(String[] args) {
        Bank bank =  new Bank();
        bank.addCustomer("Jack","Smith");
        bank.getCustomer(0).setAccount(new Account(2000));//初始化账户
        bank.getCustomer(0).getAccount().withdraw(500);//取钱
        double balance = bank.getCustomer(0).getAccount().getBalance();//余额
        System.out.println("客户:" + bank.getCustomer(0).getFirstName() + " 您的账户余额为:"
                + bank.getCustomer(0).getAccount().getBalance() + "元");
        bank.getCustomer(0).getAccount().deposit(600);//存钱

        bank.addCustomer("Lucy","Smith");
        System.out.println("银行客户数为:" + bank.getNumberOfCustomer());
    }
}
public class Account {
    private double balance;

    public  Account (double init_balance) {
        this.balance = init_balance;
    }

    public double getBalance() {
        return balance;
    }
    //存钱
    public void deposit(double amt) {
        if (amt > 0) {
            balance += amt;
            System.out.println("存钱成功!存入" + amt +"元,余额为:" + balance + "元");
        }
    }
    //取钱
    public void withdraw(double amt) {
        if (balance >= amt) {
            balance -= amt;
            System.out.println("取钱成功!取出" + amt + "元。");
        } else {
            System.out.println("余额不足!");
        }
    }
}
public class Customer {
    private String firstName;
    private String lastName;
    private Account account;

    public Customer(String f, String l) {
        this.firstName = f;
        this.lastName = l;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}
public class Bank {
    private Customer[] custs;//存放多个用户的数组
    public int numberOfCustomer;//记录用户数

    public Bank() {
        custs = new Customer[10];
    }

    //添加客户
    public void addCustomer(String f, String l) {
        Customer cust = new Customer(f, l);
        custs[numberOfCustomer] = cust;
        numberOfCustomer++;
//        customers[numberOfCustomer++] = cust;
    }

    //获取客户的个数
    public int getNumberOfCustomer() {
        return numberOfCustomer;
    }

    //获取数组指定位置上的客户
    public Customer getCustomer(int index) {
//        return customers[index];//可能报异常
        if (index >= 0 && index < numberOfCustomer) {
            return custs[index];
        }
        return null;
    }
}

* 一、package关键字的使用
* 1、为了更好的实现项目中类的管理,提供包的概念
* 2、使用package声明类或接口所属的包,声明在原文件的首行
* 3、属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”
* 4、每“.”一次,就代表一层文件目录
* 补充:同一个包下,不能命名同名的接口、类,不同的包下,可以命名同名的接口、类
import:导入
* 1、在源文件中显式的使用import结构导入指定包下的类、接口
* 2、声明在包的声明和类的声明之间
* 3、如果需要导入多个结构,则并列写出即可
* 4、可以使用"xxx.*"的方式,表示可以导入xxx包下的所有结构
* 5、如果使用的类或接口是java.lang包下定义的,则可以省略import结构
* 6、如果使用的类或接口是本包下定义的,则可以省略import结构
* 7、如果在源文件中,使用了不同包下的同名的类,则必须 至少有一个类需要以全类名的方式显示
* 8、使用“xxx.*”方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显示导入
* 9、import static:导入指定类或接口中的静态结构:属性或方法

MVC设计模式

MVC是常用的设计模式之一,将整个程序分为三个层次:视图模型层,控制器层,与数据模型层。这种将程序输入输出、数据处理,以及数据的展示分离开来的设计模式使程序结构的灵活而且清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。

模型层 model 主要处理数据

  • 数据对象封装      model.bean/domain
  • 数据库操作类      model.dao
  • 数据库                 model.db

视图层  view 显示数据

  • 相关工具类          view.utils
  • 自定义                 view.ui

控制层 controller 处理业务逻辑

  • 应用界面相关        controller.activity
  • 存放fragment        controller.fragment
  • 显示列表的适配器 controller.adapter
  • 服务相关的            controller.service
  • 抽取的基类            controller.base

 

分类: Java