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
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 > 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 > girl.age) { // return 1; // } else if (this.age < 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类
- 声明三个私有对象属性:firstName、lastName和account。
- 声明一个仅有构造器,这个构造器带有两个代表对象属性的参数(f和l)
- 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。
- 声明setAccount方法来对account属性赋值。
- 声明getAccount方法以获取account属性。
3、写一个测试程序。
- 创建一个Customer,名字叫Jane Smith,他有一个账号为1000,余额为2000元,年利率为1.23%的账户。
- 对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