饥人谷java体系课
封装与访问控制
封装
隐藏内部实现细节,只暴露出接口
好处:只需要修改接口中的内部细节,不用修改其他地方使用的这些接口
封装的实现、访问控制符
public 任何⼈都能访问
protected 只有⼦类可以访问和同⼀个包的可以访问
包是没有嵌套、包含关系的!!!!
package private 只有同⼀个包的类可以访问
private 只有⾃⼰可以访问
getter和setter与javaBean约定
getter
setter
JavaBean约定
对getter、setter方法名的约定
非boolean属性:getter方法 get属性名
setter方法 set属性名
boolean属性 getter方法 is属性名
setter方法 set属性名
JSON:将对象用字符串的方式表示出来的方法
JSON<—>java Object
对json操作的时候,只看javaBean中getter、setter方法的名字,而不看实现细节的名字
序列化和反序列化
JSON maven依赖
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>x.x.x</version></dependency>
其中 x.x.x 是版本号,根据需要使用特定版本,建议使用最新版本。
JSONAPI
可以使用 JSON.toJSONString() 将 Java 对象转换换为 JSON 对象:
JSON.parseObject(json,Student.class); 将json转换为java对象
public class Main {/*假设你正在为学校开发一个学生分数记录系统你和前端约定的JSON接口格式是:{"name": "张三","retakingExam": true,"score": 59,"fail": true // 是否挂科,如果分数低于60则返回true,代表挂科}请:1. 设计并完成Student类2. 挑选一种你喜欢的JSON类库,完成序列化/反序列化的方法*/public static void main(String[] args) {Student student = new Student();student.setName("张三");student.setScore(60);student.setRetakingExam(true);String json = serialize(student);System.out.println(json);student = deserialize(json);}// 序列化:将Student类转换成JSON字符串public static String serialize(Student student) {return JSON.toJSONString(student);}// 反序列化:将JSON字符串转换成Student对象public static Student deserialize(String json) {return JSON.parseObject(json,Student.class);}}
public class Student {// 请按照Main类的要求,补全本类/** 姓名 */private String name;/** 是否重考。true为重考,falase为非重考。 */private boolean retakingExam;/** 分数 */private int score;private boolean fail;public String getName() {return name;}public void setName(String name) {this.name = name;}public boolean isRetakingExam() {return retakingExam;}public void setRetakingExam(boolean retakingExam) {this.retakingExam = retakingExam;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}public boolean isFail() {return fail;}public void setFail(boolean fail) {this.fail = fail;}}
工厂模式
《Effective java》
使用静态工厂方法代替构造器
私有化构造器
public class Cat {private String name;private boolean cute;public boolean isCute() {return cute;}public void setCute(boolean cute) {this.cute = cute;}public String getName() {return name;}public void setName(String name) {this.name = name;}private Cat(String name,boolean cute) {this.name = name;this.cute=cute;}public static Cat newCuteCat(String name){if (name==null){return null;}return new Cat(name,true);}}
优点:
不像构造器,他是有名字的;可以描述这个方法再做什么
不像构造器,不需要去创建一个新的对象
可以返回,返回类型的子类型,提高静态工厂方法的灵活性
可以根据传递进来的参数,决定要不要创建对象以及创建什么样的对象
静态工厂返回的对象可以不存在
缺点:
没有办法被子类化
很难让开发者找到
public class Cat {private static final Cat INVALID_CAT = new Cat("Invalid cat", -1);private String name;private int age;//私有化构造器private Cat(String name, int age) {this.name = name;this.age = age;}/*** 创建一只猫的工厂方法。当传入的参数无效,即:** <p>1. age小于0 2. name是空字符串或者null时** <p>返回预先创建好的{@link #INVALID_CAT};** <p>否则,返回一只新创建的猫** @param age 年龄* @param name 名字* @return 创建的猫*/public static Cat newCat(String name, int age) {if (age<0||"".equals(name)||name==null){return INVALID_CAT;}return new Cat(name,age);}public String getName() {return name;}public int getAge() {return age;}}
类的访问控制符
public 任何都能访问
package private 包级私有,前面什么都不写,只能在同一个包中访问
private inner class 内部类,只能在同一个类中访问
java的模块系统 Java Platfrom Module System
builder模式
会定义每个属性设置的方法和和其相关的方法名,便于设置该属性
public class UserBuilder {// 请在这里使用builder模式建造User对象// 所需的接口请参阅UserBuilderTest测试类private String firstName;private String lastName;private String phoneNumber;private String address;public UserBuilder(){}public static UserBuilder anUser(){return new UserBuilder();}public UserBuilder firstName(String firstName){this.firstName=firstName;return this;}public UserBuilder lastName(String lastName){this.lastName=lastName;return this;}public UserBuilder phoneNumber(String phoneNumber){this.phoneNumber=phoneNumber;return this;}public UserBuilder address(String address){this.address=address;return this;}public User build(){return new User(firstName,lastName,phoneNumber,address);}}
public class User {/** 用户的名 */private final String firstName;/** 用户的姓 */private final String lastName;/** 用户的电话 */private final String phoneNumber;/** 用户的地址 */private final String address;public String getFirstName() {return firstName;}public String getLastName() {return lastName;}public String getPhoneNumber() {return phoneNumber;}public String getAddress() {return address;}User(String firstName, String lastName, String phoneNumber, String address) {this.firstName = firstName;this.lastName = lastName;this.phoneNumber = phoneNumber;this.address = address;}
组合与继承
继承
Object的toString()和equals()方法
toString():将对象转为字符串
equals()和==的区别
equals():方法本质也是==,在其他子类中可以被重写,可以根据重写的方法进行比较
==比较的是值,基本数据类型就比较其本身大小,但是对象直接比较的是地址。
继承中的类结构和初始化顺序
实例方法的覆盖 Override
super关键字
设计模式:模板方法
提供⼀个“模板”,实现可以覆盖模板的全部或者部分
public class Story {public final void tellStory() {startStory();story();endStory();}public void startStory() {System.out.println("开始讲故事啦");}public void story() {System.out.println("从前有个老和尚");}public void endStory() {System.out.println("故事讲完啦");}public static void main(String[] args) {new Story().tellStory();}}
//1.继承Story类public class MonsterStory extends Story {// 请补全本类,使得main方法可以输出以下内容://// 开始讲故事啦// 从前有个老妖怪// 故事讲完啦// 你还想听吗//重写需要修改的方法@Overridepublic void story() {System.out.println("从前有个老妖怪");}//重写方法,并调用父类的该方法@Overridepublic void endStory() {super.endStory();System.out.println("你还想听吗");}public static void main(String[] args) {new MonsterStory().tellStory();}}
向上、向下转型
instanceof 判断类型
判断一个地址是不是某一个类的对象实例,还可以判断某一个对象实例是不是实现了某个接口
null instanceof xxx ==false 右边一定是一个类
当需要⼀个⽗类型时,总可以传递⼀个⼦类型
向下转型有可能是不安全的,需要强制类型转换
final关键字与单例模式
final声明变量,变量成为不可变的(必须初始化)
局部变量/⽅法参数
成员变量
常量与单例
final修饰的变量只能被赋值一次
final修饰的好处:可以保证它是线程安全的,因为它不会被改变
final修饰的对象指向的地址是不能改变的,当对象中的数据是可以改变的
final在⽅法上的声明:禁⽌继承/覆盖/重写此⽅法
final在类声明上的使⽤:禁⽌继承此类
String、Integer都是final修饰的,不可被继承
单例模式
public class SingleObject {//创建 SingleObject 的一个对象private static SingleObject instance = new SingleObject();//让构造函数为 private,这样该类就不会被实例化private SingleObject(){}//获取唯一可用的对象public static SingleObject getInstance(){return instance;}public void showMessage(){System.out.println("Hello World!");}}
public class SingletonPatternDemo {public static void main(String[] args) {//不合法的构造函数//编译时错误:构造函数 SingleObject() 是不可见的//SingleObject object = new SingleObject();//获取唯一可用的对象SingleObject object = SingleObject.getInstance();//显示消息object.showMessage();}}
组合
多态
允许将子类类型的指针赋值给父类类型的指针,把不同的子类对象都当作父类来看
实例⽅法默认是多态的
在运⾏时根据this来决定调⽤哪个⽅法
静态⽅法没有多态
参数静态绑定,接收者动态绑定
多态只选择接受者的类型,不选择参数的类型
public class Base {public void print(BaseParam param){System.out.println("i am base,the param is baseParam");}public void print(SubParam param){System.out.println("i am base,the param is subParam");}}public class Sub extends Base{@Overridepublic void print(SubParam param) {System.out.println("i am sub,the param is subParam");}@Overridepublic void print(BaseParam param) {System.out.println("i am sub,the param is baseParam");}}public class BaseParam {}public class SubParam extends BaseParam{}
public class Main {public static void main(String[] args) {Base base = new Sub();BaseParam param=new SubParam();base.print(param);}}//输出结果:i am sub,the param is baseParam
设计模式:策略模式
public class PriceCalculator {// 使用策略模式重构这个方法,实现三个策略:// NoDiscountStrategy 不打折// Discount95Strategy 全场95折// OnlyVipDiscountStrategy 只有VIP打95折,其他人保持原价// 重构后的方法签名:// public static int calculatePrice(DiscountStrategy strategy, int price, User user)public static int calculatePrice(DiscountStrategy strategy, int price, User user) {return strategy.discount(price, user);}}
public class DiscountStrategy {public int discount(int price, User user) {throw new UnsupportedOperationException();}}
public class NoDiscountStrategy extends DiscountStrategy{@Overridepublic int discount(int price, User user) {return price;}}
public class Discount95Strategy extends DiscountStrategy{@Overridepublic int discount(int price, User user) {return (int) (price * 0.95);}}
public class OnlyVipDiscountStrategy extends DiscountStrategy{@Overridepublic int discount(int price, User user) {if (user.isVip()) {return (int) (price * 0.95);} else {return price;}}}
抽象类与接口
抽象类
abstract声明的类
抽象类可以有普通类的所有东西
可以声明抽象方法,抽象方法必须声明在抽象类里
不可实例化
可以实例化的东⻄⼀定要补全所有的⽅法体。
可以包含抽象⽅法 - ⾮private/static
可以包含普通类的任何东⻄
接口
接口不是类,只代表一种功能
类实现接口 implements 关键字
一个类只能继承一个类,但能实现多个接口
所有实现接口的类都必须实现接口的所有方法,因此,接口在使用之后就不可修改
打破向后兼容性
接口可以包含
若⼲个⽅法(默认public)
若⼲个常量(默认public static final)
extends 接⼝
默认⽅法
java8之后引入default默认接口方法,其不是实现接口必须实现的方法
同一个类实现不同的接口中有同名方法时,编译时就会给出警告
什么时候使用接口,什么时候使用抽象类
接口和抽象方法的异同
同:1.都是抽象的 2.不可实例化 3.可以包含抽象方法(没有方法体,非ststic、private、final的)
不同:1.抽象类是类,可以包含类的一切东西,但是接口只能包含受限的成员和方法,java8之后可以加default的默认方法
2.抽象类只能单一继承,而接口是可以多继承的,甚至继承多次
接口实战:comparable
package com.github.hcsp.polymorphism;import java.io.IOException;import java.util.Arrays;import java.util.Collections;import java.util.List;public class Point implements Comparable<Point>{private final int x;private final int y;// 代表笛卡尔坐标系中的一个点public Point(int x, int y) {this.x = x;this.y = y;}public int getX() {return x;}public int getY() {return y;}@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (o == null || getClass() != o.getClass()) {return false;}Point point = (Point) o;if (x != point.x) {return false;}return y == point.y;}@Overridepublic int hashCode() {int result = x;result = 31 * result + y;return result;}@Overridepublic String toString() {return String.format("(%d,%d)", x, y);}// 按照先x再y,从小到大的顺序排序// 例如排序后的结果应该是 (-1, 1) (1, -1) (2, -1) (2, 0) (2, 1)public static List<Point> sort(List<Point> points) {Collections.sort(points);return points;}public static void main(String[] args) throws IOException {List<Point> points =Arrays.asList(new Point(2, 0),new Point(-1, 1),new Point(1, -1),new Point(2, 1),new Point(2, -1));System.out.println(Point.sort(points));}@Overridepublic int compareTo(Point point) {if (this.x>point.x){return 1;}else if (this.x<point.x){return -1;}if (this.y>point.y){return 1;}else if (this.y<point.y){return -1;}return 0;}}
内部类
⽤途:实现更加精细的封装
可以访问外围类的实例⽅法
⾮静态内部类
和⼀个外围类实例相绑定
可以访问外围类实例的⽅法
静态内部类
不和外围类实例相绑定
不可以访问外围实例的⽅法
原则:永远使⽤静态内部类,除⾮编译报错
匿名内部类
直接通过new的方式创建无名类
文件过滤器
package com.github.hcsp.polymorphism;import java.io.File;import java.io.IOException;import java.nio.file.*;import java.nio.file.attribute.BasicFileAttributes;import java.util.ArrayList;import java.util.List;public class FileFilter {public static void main(String[] args) throws IOException {Path projectDir = Paths.get(System.getProperty("user.dir"));Path testRootDir = projectDir.resolve("test-root");if (!testRootDir.toFile().isDirectory()) {throw new IllegalStateException(testRootDir.toAbsolutePath().toString() + "不存在!");}List<String> filteredFileNames = filter(testRootDir, ".csv");System.out.println(filteredFileNames);}/*** 实现一个按照扩展名过滤文件的功能** @param rootDirectory 要过滤的文件夹* @param extension 要过滤的文件扩展名,例如 .txt* @return 所有该文件夹(及其后代子文件夹中)匹配指定扩展名的文件的名字*/public static List<String> filter(Path rootDirectory, String extension) throws IOException {List<String> fileName = new ArrayList<>();Files.walkFileTree(rootDirectory, new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {if (file.getFileName().toString().endsWith(extension)) {fileName.add(file.getFileName().toString());}return FileVisitResult.CONTINUE;}});return fileName;}}
