一、程序设计原则:
设计模式;
别人问你设计模式是啥玩意?为了显得很专业,你可以淡淡的说道:“它是一套被反复使用,被多数人知晓的,经过分类编目的,代码设计经验的总结”(心道:尼玛,还好有度娘!)
想要学设计模式,程序设计的6大原则,怎么可以会不清楚?
开-闭原则(政治家,只开放不改革):对修改关闭,对扩展开放。
对原有的功能(代码)的修改是关闭(修改的越少越好)
还可以很方便的对原有功能进行扩展。
注:目测为黑社会大哥属性,其他小弟都要围着它转;它更像是其他五个原则的总纲,前五个原则就是围着它转的,只要我们尽量的遵守前五个原则,那么设计出来的系统应该就比较符合开闭原则了,相反,如果你违背了太多,那么你的系统或许也不太遵循开闭原则。
单一原则(大工匠,做事专一):每个类都只负责单一的功能,并尽量把这一个功能做到极致!
依赖倒置原则(艺术家,爱抽象派):高层模块不该依赖于低层模块,二者都应该依赖于抽象,抽象不应该依赖于细节,细节应该依赖于抽象。
接口最小化原则/接口隔离原则(大龄剩女,挑三拣四):强调的是一个接口拥有的行为应该尽可能的小。
注:最小接口原则一般我们是要尽量满足的,如果实在有多余的方法,这时候就轮到缺省适配器上场了。
里氏替换原则(大孝子,父命不敢违):一个子类应该可以替换掉父类并且可以正常工作。隐含说,子类一般不该重写父类的方法, 防止子类不能实现和父类一样的功能;
注:很多情况下,我们不必太理会它,比如模板方法模式,缺省适配器,装饰器模式等一些设计模式,就完全不搭理它。
迪米特原则/最小知道原则(奇葩少年,梦想是患上自闭症):一个类应当不要让外部的类知道自己太多,也不要知道外部类太多;(高内聚,低耦合)
二、多态polymorphism
多态的概念:多态是一种能力,一种可以父类引用指向子类对象,并可以在运行期根据对象实际的类型执行对应类型的方法的功能。
多态形成的必要的条件:
1:继承。
2:父类引用指向子类对象。
3:子类重写父类的方法。父类引用调用被重写的方法。
1:使用父类类型作为方法的参数,传递的是子类对象。
2:使用父类类型作为方法的返回值,返回的是子类对象。
例1:
public class TestAnimal {
public static void main(String[] args) {
Animal animal = new Animal();
animal.sound();
Tiger tiger = new Tiger();
tiger.sound();
Animal ani = new Tiger();
ani.sound();
}
}
class Animal{
void sound(){
System.out.println("小动物 吱哇乱叫!");
}
}
class Tiger extends Animal{
@Override
void sound() {
System.out.println("老虎 ヾ(≧O≦)〃嗷~ 的一声~~~");
}
}
例2:
//各个国家的人在餐厅吃饭
public class TestRestaurant {
public static void main(String[] args) {
Restaurant restaurant = new Restaurant("卢旺达饭店");
restaurant.showEat(new Chinese("伟大的炎黄子孙"));
restaurant.showEat(new America("美利坚合众国"));
restaurant.showEat(new Japanese("小日本"));
restaurant.showEat(new Indian("阿三"));
restaurant.showEat(new Italian("意大利"));
System.out.println(restaurant);
}
}
//在一定程度上违背了开闭原则,只要添加一个新的Person 的子类,那么就需要在 Restaurant 重载添加一个 showEat 的方法。
// Person 引用指向 具体的其他的子类的对象。
// 多个国家的人继承了Person
// 多个国家的类 重写 了Person 类的eat 方法。
class Restaurant {
private String name;
Restaurant(String name) {
this.name = name;
}
// void showEat(Chinese chinese){
// chinese.eat();
// }
//
// void showEat(America america){
// america.eat();
// }
//
// void showEat(Japanese japanese){
// japanese.eat();
// }
//
// void showEat(Indian indian){
// indian.eat();
// }
void showEat(Person person){
person.eat();
}
@Override
public String toString() {
return "Restaurant [name=" + name + "]";
}
}
class Person {
//国家的名字
private String countryName;
Person(String countryName) {
this.countryName = countryName;
}
void eat(){
System.out.println(countryName + " 的人 在吃饭!");
}
public String getCountryName() {
return countryName;
}
}
class Chinese extends Person{
public Chinese(String countryName) {
super(countryName);
}
@Override
void eat() {
System.out.println(getCountryName() + "\t 使用 筷子 吃饭!可好吃了!");
}
}
class America extends Person{
public America(String countryName) {
super(countryName);
}
@Override
void eat() {
System.out.println(getCountryName() + "\t 使用刀叉 吃 四顿饭");
}
}
class Japanese extends Person{
public Japanese(String countryName) {
super(countryName);
}
@Override
void eat() {
System.out.println(getCountryName() + "\t 喜欢杀戮大海中的鲨鱼宝宝,然后吃掉他们的鱼鳍!真残忍啊!");
}
}
class Indian extends Person{
public Indian(String countryName) {
super(countryName);
}
@Override
void eat() {
System.out.println(getCountryName() + "\t 用脚揉面,然后用抓着吃!");
}
}
class Italian extends Person{
public Italian(String countryName) {
super(countryName);
}
@Override
void eat() {
System.out.println(getCountryName() + "\t 吃意大利面!味道马马虎虎吧!");
}
}
例3:
package com.bjsxt.polymorphism.oop0524;
//人演奏乐器(大鼓Drum,吉他Guitar,钢琴Piano,小号Trumpet,三弦Trichord)
public class TestInstrument {
public static void main(String[] args) {
People people = new People();
people.play(new Drum(10000, "大鼓"));
people.play(new Guitar(5000, "吉他"));
people.play(new Trichord(20000, "三弦"));
people.play(new Trumpet(1000, "小号"));
people.play(new Piano(200000, "钢琴"));
}
}
//所有的乐器的父类
class Instrument{
private int price;
private String name;
public Instrument() {
}
Instrument(int price, String name) {
super();
this.price = price;
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Instrument [price=" + price + ", name=" + name + "]";
}
//这个父类的方法的实现没有太大的意义,空实现,该方法存在的意义在于被子类重写。
void sound(){
}
}
class Drum extends Instrument{
Drum(int price, String name) {
super(price, name);
}
@Override
void sound() {
System.out.println(getName() + "\t被用力的敲打,发出了。。咚咚咚。。。的声音");
}
}
class Guitar extends Instrument{
Guitar(int price, String name) {
super(price, name);
}
@Override
void sound() {
System.out.println(getName() + "\t 拨弄了几下,发出了,叮叮叮的声音!");
}
}
class Trichord extends Instrument{
Trichord(int price, String name) {
super(price, name);
}
@Override
void sound() {
System.out.println(getName() + "\t 拨弄了几下,发出了,当~当~当~的声音!");
}
}
class People{
// void play(Trichord trichord){
// trichord.sound();
// }
// void play(Drum drum){
// drum.sound();
// }
// void play(Guitar guitar){
// guitar.sound();
// }
// void play(Trumpet trumpet){
// trumpet.sound();
// }
void play(Instrument instrument){
instrument.sound();
}
}
class Trumpet extends Instrument{
Trumpet(int price, String name) {
super(price, name);
}
@Override
void sound() {
System.out.println(getName() + "\t 被吹了几下,发出了 嘟嘟嘟的声音");
}
}
class Piano extends Instrument{
Piano(int price, String name) {
super(price, name);
}
@Override
void sound() {
System.out.println(getName() + "\t 被弹了几下,发出了,叮当叮当的声音!!!");
}
}
三、使用多态解释方法重写
1:子类的重写方法访问权限必须大于等于父类的?
在编译期对象无法确定在运行期具体调用执行的哪个方法。
如果子类降低了被访问的权限,那么如果在运行期执行的是子类重写方法,那么可以造成被重写的方法访问不到。
2:返回类型:
可以是父类的方法的返回类型的子类型。
因为这样做是安全的,子类对象的具有的功能是大于等于父类的。父类对象可以执行的功能,子类对象肯定没问题。
3:子类重写的方法可能产生的问题要小于等于父类的。
如果一个方法编译、运行的时候可能会有一些问题,那么我们必须通过代码加以处理。
如果子类的方法产生的问题更多,那么处理父类方法的代码可能解决不掉因为多态而调用的子类的方法产生的问题。
四、多态转型
//自动向上类型转换(小类型向大类型自动转换)
//因为这样做是安全的。老虎当动物来用了。因为动物能做的,老虎都能做。
Animal ani = new Tiger();
//强制向下(大类型向小类型转换) 可不可以将一个动物 当老虎来用。 不能将将一个当动物用的兔子,当老虎用。
//不安全。
Animal rabbit = new Rabbit();
//强制向下类型转换的语法 ,只有当一个对象的实际类型是强制转换的类型的类型的时候,那么这种向下强转才可以成功。
Tiger tiger = (Tiger)ani;
tiger.eatRabbit();
1:自动向上是 多态的基础。
2:强制向下,只有当我们需要使用子类的特有的方法的时候,才有必要将父类类型的对象强制转换为子类类型。
//通过什么样的方式可以避免向下强转的意外。
//instanceof 的主要用途,用于判断一个对象是否可以强制转换为指定类型的对象。
if(rabbit instanceof Tiger){
Tiger tiger1 = (Tiger)rabbit;
}
五、多态和重载
public class A{
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
//a2调用的方法必须是A中存在的方法,show(A obj) 方法又被子类重写,所以执行的是子类中重写的方法
System.out.println(a2.show(b)); //B and A ???
//a2调用的是A中存在的方法。 B没有重写show(D obj) 所以调用的就是A 中的show(D obj)
System.out.println(a2.show(d)); //A and D ???
//b调用的是B 中有的方法 show(D obj) 是从A中继承下来的。直接调用即可。
System.out.println(b.show(d)); //A and D ???
System.out.println(a1.show(b)); //A and A
System.out.println(a1.show(c)); //A and A
System.out.println(a1.show(d)); //A and D
System.out.println(a2.show(c)); //B and A
System.out.println(b.show(b)); //B and B
System.out.println(b.show(c)); //B and B
}
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return ("A and A");
}
}
class B extends A{
//B自定义的方法
public String show(B obj){
return ("B and B");
}
//重写
public String show(A obj){
return ("B and A");
}
//继承下来的方法
public String show(D obj){
return ("A and D");
}
}
class C extends B{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
public String show(D obj){
return ("A and D");
}
}
class D extends B{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
public String show(D obj){
return ("A and D");
}
}
六、简单工厂模式
java 中 有 23 种设计模式。
设计类的要求:高内聚、低耦合。
高内聚:类的内部的成员之间的关系是非常紧密的。
低耦合:类和类之间的耦合度要尽量小。
简单工厂模式的作用:降低类和类之间的耦合度的。
/**
* 简单工厂模式,用来创建对象的
*
*/
public class MyFactory {
//写一个工厂方法,通过传入的字符串的值,创建对应的类的对象并返回。
public static Person createPerson(String className){
Person person = null;
//根据类名,给person 赋值不同的子类对象
switch(className){
case "Chinese":
person = new Chinese("炎黄子孙中国人");
break;
case "America":
person = new America("美国佬");
break;
case "Japanese":
person = new Japanese();
break;
case "Indian":
person = new Indian("阿三");
break;
case "Italian":
person = new Italian("意大利");
break;
}
return person;
}
}
七、单例设计模式
23 种设计模式中的很重要的一种。
作用:如果某一个类在一工程中只希望创建该类的唯一的一个对象。那么就可以使用单例设计模式,保证该类只被实例化一次。
单例设计模式:SingleTon。
如何去设计一个单例类。
public class TestSingleTon {
public static void main(String[] args) {
MySingltTon mySingltTon = MySingltTon.getInstance();
System.out.println(mySingltTon.getData());//0
mySingltTon.setData(10);
System.out.println(mySingltTon.getData());//10
MySingltTon mySingltTon2 = MySingltTon.getInstance();
System.out.println(mySingltTon2.getData());//10
}
}
////需要只能被实例化一次的那个单例类。
//class MySingltTon{
// //只执行一次的代码,在类加载的时候执行
// //饿汉模式 可能会导致 启动延迟
// private final static MySingltTon singltTon = new MySingltTon();
//
// //私有化构造方法
// private MySingltTon() {
// }
//
// //写一个创建本类对象的方法。
//
// //写一个得到唯一实例的方法
// public static MySingltTon getInstance(){
// return singltTon;
// }
//
//}
//懒汉模式
class MySingltTon{
private int data;
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
private static MySingltTon singltTon;
private MySingltTon() {
}
//懒汉模式 第一使用该唯一实例 的时候进行对象的初始化
//写一个得到唯一实例的方法
public static MySingltTon getInstance(){
if(singltTon == null){
singltTon = new MySingltTon();
}
return singltTon;
}
}
八、final
final:可以用来修饰变量,让变量具有了不可被修改的属性。 不可变的变量。
final 还可以修饰什么内容?
1:修饰变量: 终态变量。
2:修饰方法: 终态方法,不能被子类重写。
3:修饰类: 终态类,不能有子类。不能被其他的类继承。
九、抽象类
概念:如果一个类被关键字abstract 修饰 那么该类就是抽象类。
抽象类特点:
1:抽象类是不允许被实例化的。
2:抽象类只能作为类继承层次上层类,作为父类出现。
作用:作为父类,被其他的类继承。
注意:如果一个抽象类中包含了抽象方法,那么它的子类要么声明成抽象的,要么实现所有的父类的抽象方法。
抽象类出现的意义:如果在做类的设计的时候,不希望设计的类被实例化,只作为父类出现,那么就可以将该类声明成抽象的类。使用abstract 修饰一下。
1:抽象类中一定有抽象的方法?
答:不一定的。
2:有抽象方法的类,一定是抽象类?
答:对的。
3:抽象类是否可以用final 修饰?
答:不可以,abstract 和 final 是互斥的。
4:静态方法是否可以声明成抽象方法?
答:不可以的。静态的方法可以被继承,不能被重写。抽象方法需要被子类实现。语义有冲突,static abstract 互斥存在。
5:抽象类中定义的抽象方法,每一个抽象的方法都是定义了一个规则!!
答:父类在定义抽象方法的时候,对于子类实现抽象方法的功能是有要求的。但是对于实现的细节没有要求。
子类在实现的时候,必须按照父类的规则要求去实现功能,不然最终可能无法达到预期效果。
6:类的实例成员变量是否可以实现多态?
答:不可以实现多态。变量的值取决于对象中的变量的声明的类型,而不是对象中的变量的实际所在的类型。
7:静态的成员方法是否可以实现多态?
答:不可以。不能重写何来多态。
总结:多态是对象的多态,只针对于对象的实例方法。
多态的简单实现:
十、抽象类和非抽象类的异同:
相同点:
1:都是类,都是用来描述对象的。都是作为模版来使用。
2:非抽象类包含的类中的成员类型,,抽象类中都可以存在。
不同点:
1:抽象类不能被实例化,非抽象的可以被实例化。
2:抽象类只能作为父类使用,非抽象的既可以作为父类(没有final 修饰的)也可以不作为父类使用。
3:抽象类中可以包含抽象方法,非抽象不可以。
4:定义的方式不同,抽象类用abstract 修饰,非抽象不允许用abstract。
十一、equals
equals:Object 类的方法:
public boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系:
自反性:对于任何非空引用值x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
传递性:对于任何非空引用值x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
对于任何非空引用值x,x.equals(null) 都应返回 false。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。
注意:当此方法被重写时,通常有必要重写hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
参数:
obj - 要与之比较的引用对象。
返回:
如果此对象与obj 参数相同,则返回 true;否则返回 false。
==:判断等号
1:如果比较的两个变量的类型是基本数据类型,那么比较的值是否相等。
2:如果比较的是引用数据类型。比较的是对象的引用,首地址。
对于引用数据类型来说,如果想比较两个对象的内容,不能使用== 只能通过方法来实现。
Object 类的equals 方法就是做这个的。
但是Object 类的 equals 的默认实现比较的也是地址。
因此,子类需要重写equals 方法。
例:
public class TestEquals {
public static void main(String[] args) {
Student s1 = new Student(12, "小刚", "男");
Student s2 = new Student(12, "小刚", "男");
System.out.println(s1 == s2);//false
// System.out.println(s1.equals(s2));//Object类的比较 也是false。
System.out.println(s1.equals(s1));//true
System.out.println(s1.equals(null));//false
System.out.println(s1.equals("123"));//false
System.out.println(s1.equals(s2));//true
}
}
class Student{
private int age;
private String name;
private String gender;
public Student() {
}
Student(int age, String name, String gender) {
super();
this.age = age;
this.name = name;
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student [age=" + age + ", name=" + name + ", gender=" + gender + "]";
}
// @Override
public boolean equals(Object obj) {
// obj 是否为null
if(obj == null){
return false;
}
//obj 和当前对象一样
if(obj == this){
return true;
}
if(!(obj instanceof Student)){
return false;
}
//比较属性
Student s = (Student)obj;
if(s.age != this.age)
return false;
if(!s.name.equals(this.name))
return false;
if(!s.gender.equals(this.gender))
return false;
return true;
}
}