整理了一份近期的Java学习笔记,希望能对大家有所帮助。
如果其中有问题可以进行一起探讨,学习和交流。
微信:1665925316。
java基础(面向对象):就近取用原则。
-
一块堆内存可以被多个栈内存所指向。(引用传递的实质)
-
垃圾空间指的就是没有任何栈内存指向的堆内存空间。
-
编写类的时候,类中的所有属性必须使用private进行封装。
-
数组要发生引用和传递不要使用【】。
-
”==“ 本身是进行数值比较的,而现在如果用在了对象之中,那么所比较的就应该是两个对象所保存的内存的数值,所以属于地址数值比较,而并没有比较对象的内容。
-
字节并不适合处理中文,而只有字符适合于处理中文,并且按照程序的概念来讲,一个字符等于两个字节,字节只适合于处理二进制数据。
-
字符串常量一旦声明则不可改变,字符串对象的内容改变依靠的是地址的引用关系变更。
-
简单java的名称 = 实体表名称;【实际开发中简单Java类的设计原则】。
简单java类的属性 = 实体表的字段;
简单Java类的一个对象 = 表的一行记录;
对象数组 = 表的多行记录;
外键关系 = 引用配置;
-
static属性能够直接通过类名称调用(访问static属性都使用类名称)。
关于static属性与非static属性定义的选择:* 在定义类99%的情况下是不会考虑static属性的。
- 如果需要描述共享属性的概念或者不希望受到实例化对象的控制的时候使用static属性。
3.static方法
- 所有static方法不允许调用非static定义的属性或者方法。
- 所有的非static方法允许访问static属性或方法。
- 使用static方法的目的:某些方法不希望受到类的限制,即:可以在没有实例化对象的时候进行执行。
4.执行顺序
- 静态块>构造块>构造方法。
- 静态块的目的是为static对象初始化
5.封装的属性如果要被外部访问,那么需要写getter方法。
6.重载和覆写的区边。
区边 | 重载 | 覆写 |
---|---|---|
英文单词 | OverLonding | Override |
概念 | 方法名称相同,参数的个数及类型不同 | 方法名称、返回值类型、参数的类型及个数完全相同 |
范围 | 发生在一个类中 | 发生在关系继承之中 |
限制 | 没有权限要求 | 被覆写的方法不能拥有比父类更为严格的访问权限 |
- 方法重载的时候返回值可以不同,但是良好的设计上要求返回类型一致。
- 在定义属性的时候尽量不要使用重名。
7.super和this的区边。
区边 | this | super |
---|---|---|
概念 | 访问本类中的属性和方法 | 由子类访问父类中的属性和方法 |
查找范围 | 先查找本类,如果本类没有则调用父类 | 不查找本类而直接调用父类定义 |
特殊 | 表示当前对象 |
2.2、定义排序扩展类:SortArray
如果要进行排序的处理操作,那么肯定在取得了全部数据的时候里面的内容应该是排序好的,同时在该类操作的过程之中应该继续具备:数据追加、数组扩充、取得全部数据(父类中的getData()方法作为一个获取数据的标准,这个方法应该继续保留)。
package com.qiao.test02.ArrayTest;
class Array{ //定义一个专门进行数组的操作类
private int data []; //定义一个整形数组,大小由外部类决定。
private int foot = 0; //进行数据的角标的操作
public Array(int len){ //如果要想使用Array类,必须先定义数组大小。
if(len>0){ //一个正常的数组大小。
this.data = new int[len]; //开辟新数组。
}else {
this.data = new int[1]; //开辟一个空间。
}
}
//动态扩展,如果此处传入一个3,则表示在已有的长度上数组长度追加了3(5+3=8)
public void inc(int num){
int newData [] = new int[this.data.length+num];
System.arraycopy(this.data,0,newData,0,this.data.length);
this.data = newData; //改变原始数组指向
}
public boolean add(int num){
if(this.foot >= this.data.length){ //没空间了。
return false;
}
//先进行数组的数据保存,而后foot的内容加1
this.data[this.foot++] = num;
return true;
}
public int[] getData(){ //取得全部数组数据
return this.data; //返回数组内容
}
}
//可以继承父类中已经存在的所有操作方法。
class SortArray extends Array{
//父类中无明确无参构造方法,所以子类必须明确调用父类中的构造方法
public SortArray(int num){
super(num); //父类中支持数组创建了
}
//父类中的取得数据的方法的名称很标准,但是功能不足,又希望继续使用这个方法名称,那么就需要对方法进行扩充,扩充就是方法覆写的核心作用。
public int[] getData(){
java.util.Arrays.sort(super.getData());
return super.getData(); //引用传递
}
}
public class TestDemo01 {
public static void main(String[] args) {
SortArray arr = new SortArray(5);
System.out.println(arr.add(3));
System.out.println(arr.add(1));
System.out.println(arr.add(2));
System.out.println(arr.add(8));
System.out.println(arr.add(6));
System.out.println(arr.add(7));
arr.inc(3); //扩充数组
System.out.println(arr.add(10));
System.out.println(arr.add(20));
System.out.println(arr.add(30));
int result[] = arr.getData(); //接收全部数据
for(int x=0; x<result.length; x++){
System.out.print(result[x]+"、");
}
}
}
也就是说不同的子类可能要针对于方法进行部分的扩展。
2.3、定义反转子类:ReverseArray。
反转子类的最大特点在于,取得的数据是其保存顺序的相反内容。整体的实现分格实际上和排序数组子类是一样的。
class ReverseArray extends Array{
//必须知道数组大小
public ReverseArray(int len){ //必须明确调用父类
super(len);
}
public int[] getData(){
int center = super.getData().length/2;
int head = 0;
int tail = super.getData().length-1;
for(int x=0; x<center; x++){
int temp = super.getData()[head];
super.getData()[head] = super.getData()[tail];
super.getData()[tail] = temp;
head++;
tail--;
}
return super.getData();
}
}
本程序完美的表现出来了对继承的概念讲解以及覆写的核心意义。
.2、具体方法:final关键字
在java中final被称为终接器,可以使用final来定义类、方法、属性。
1、使用final定义的类不能有子类;
2.使用final定义的方法不允许被子类所覆写;
3.使用final定义的变量就成为了常量,常量必须在声明时赋值,并且不允许修改。
- 在开发之中如果要定义常量往往会使用public static final 来定义全局常量。
- 而且常量的标识符必须全部采用大写字母的形式出现。
.2、具体方法:多态性。
在Java里面对于多态的核心表现主要有以下两点:
- 方法的多态性:
|- 方法的重载:同一个方法名称可以根据参数的类型及个数的不同调用不同的方法体;
|- 方法的覆写:同一个父类的方法,可能根据实例化的子类不同也有不同的实现;
- 对象的多态性(前提:方法覆写):
|- 【自动,90%】对象的向上转型:父类 父类对象 = 子类实例;
|- 【强制,1%】对象的向下转型:子类 子类对象 = (子类)父类实例;
|- 9%是不进行转型,列如:String;
**范例:**回顾一个简单程序。
class A{
public void print(){
System.out.println("【A】public void print{}");
}
}
class B extends A{
public void print(){
System.out.println("【B】public void print{}");
}
}
public class JavaTest001 {
public static void main(String[] args) {
B b = new B(); //实例化子类对象
b.print(); //调用被覆写的方法
}
}
于是可以将以上的代码进一步变化,变为向上转型。
**范例:**实现向上转型。
A a = new B(); //向上转型
a.print();
不管是否发生了向上转型,那么其核心的本质还是在于:你使用的是哪一个子类(new在哪里),你调用的方法是否被子类所覆写了。
需要用到子类扩充操作的时候就要采用向下转型
**范例:**实现向下转型。
class A{
public void print(){
System.out.println("【A】public void print{}");
}
}
class B extends A{
public void print(){
System.out.println("【B】public void print{}");
}
public void funB(){ //只有子类有
System.out.println("【B】public void funB{}");
}
}
public class JavaTest001 {
public static void main(String[] args) {
A a = new B(); //向上转型
a.print();
//这个时候父类能够调用的方法自能是自己定义的方法。
B b = (B) a; //向下转型
b.funB();
}
}
【此概念一般开发中用不到】但是并不是所有的父类对象都可以实现向下转型:如果要想进行向下转型操作之前一定要首先发生向上转型,否则在转型时会出现:ClassCastException。
如果向下转型可能存在有隐患,那么如何转型?最好的做法是先进行判断,而后再进行转型,那么就可以依靠instanceof关键字来实现,此关键字使用语法如下:
- 子类对象 instanceof 类,返回的是boolean型数据;
**范例:**观察instanceof 关键字
class A{
public void print(){
System.out.println("【A】public void print{}");
}
}
class B extends A{
public void print(){
System.out.println("【B】public void print{}");
}
public void funB(){ //只有子类有
System.out.println("【B】public void funB{}");
}
}
public class JavaTest001 {
public static void main(String[] args) {
A a = new B(); //实例化父类对象
System.out.println(a instanceof A);
System.out.println(a instanceof B);
//以后对于子类的特殊操作尽量慎用
if(a instanceof B){ //避免ClassCastException问题
B b = (B) a;
b.funB();
}
}
}
思考:这种转化有什么意义?
范例:要求定义一个方法,而这个方法可以接收Person类的所有子类实例,并调用Person类的方法;
class Person{
public void takeoff(){ //脱
System.out.println("脱掉...");
}
}
class Student extends Person{
public void takeoff(){
System.out.println("一件件脱...");
}
}
class Worker extends Person{
public void takeoff(){
System.out.println("直接卷了...");
}
}
public class JavaTest001 {
public static void main(String[] args) {
in(new Student());
in(new Worker());
}
public static void in(Person per){
per.takeoff(); //所有的人不管什么种类都按照统一的方式进行。
}
}
通过以上的分析就可以清楚,对象的向上转型有一个最为核心用途:操作参数统一。
1.对象多态性实现的核心在于方法的覆写;
2.通过对象的向上转型可以实现接收参数的统一,而向下转型可以实现子类扩充方法的调用(一般不操作向下转型);
3.两个没有关系的类对象是不能够进行转型的,一定会发生ClassCastException,所有向下转型存在有安全隐患。
.2、抽象类。
【90%的正规代码】 以后所有进行的项目开发过程中,绝对不要出现一个类去继承一个已经实现好的类,而自能够继承抽象类和接口。
对象多态性的核心本质在于方法的覆写上,如果说现在子类没有去进行指定方法的覆写,这样的操作就有些不合要求的。所以如果要对子类的方法进行一些强制的要求就必须采用抽象类来解决。
抽象类的基本概念:
抽象类只是在普通类的基础上扩充了一些抽象方法而已。所谓的抽象方法指的是只声明而未实现(没有方法体)的方法,所有的抽象方法要求使用abstract关键字来进行定义,并且抽象方法所在的类也一定要使用abstract定义类,表示抽象类。
**范例:**定义一个抽象类。
abstract class A{
private String msg = "www.qiao.com"; //属性
public void print(){ //普通方法
System.out.println(msg);
}
//{}为方法体,所有的抽象方法上是不包含有方法体的。
public abstract void fun(); //抽象方法
}
public class JavaTest001 {
public static void main(String[] args) {
}
}
现在发现抽象类就是比普通类多了一些抽象方法而已。
抽象类中本包含有抽象方法,而抽象方法与普通方法最大的区边在于其没有方法体,即:不知道具体的实现,而如果现在产生了实例化对象,则意味着可以调用类中的所有操作。
对于抽象类的使用原则:
- 所有的抽象类必须要有子类。
- 抽象类的子类(不是抽象类)必须覆写抽象类中的全部抽象方法;
|- 方法覆写一定要考虑到权限问题:抽象方法可以使用任意权限,要求权限尽量都用public
- 抽象类的对象可以通过对象多态性,利用子类为其实例化。
**范例:**使用抽象类。
abstract class A{
private String msg = "www.qiao.com"; //属性
public void print(){ //普通方法
System.out.println(msg);
}
//{}为方法体,所有的抽象方法上是不包含有方法体的。
public abstract void fun(); //抽象方法
}
//一个子类只能够利用extends来继承抽象类,所有依然存在有单继承局限
class B extends A{ //定义抽象类的子类
public void fun(){
System.out.println("hello world!");
}
}
public class JavaTest001 {
public static void main(String[] args) {
A a = new B(); //实例化子类对象
a.fun(); //被子类所覆写的方法
}
}
抽象类的相关规定:
1.抽象类只是比普通类多了一些抽象方法的定义而已,所以在抽象类之中依然允许提供有构造方法,并且也会遵守子类对象的实例化流程。实例化子类对象前一定要先去调用父类的构造方法。
**范例:**在抽象类中定义构造方法。
abstract class Person{
private String name;
private int age;
public Person(){
System.out.println("*******************");
}
public abstract String getInfo(); //抽象方法
}
class Student extends Person{
private String school;
public Student(){
System.out.println("#########################");
}
@Override
public String getInfo(){
return null;
}
}
public class JavaTest001 {
public static void main(String[] args) {
new Student();
}
}
如果说现在父类中没有无参构造,那么子类就必须通过super()指明要调用的父类构造方法。
abstract class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return this.name;
}
public int getage(){
return this.age;
}
public abstract String getInfo(); //抽象方法
}
class Student extends Person{
private String school;
public Student(String name,int age,String school){
super(name,age); //子类构造必须明确调用父类构造
this.school = school;
}
@Override
public String getInfo(){
return "【Student】name="+super.getName()+"、aeg="+super.getage()+"、school="+this.school;
}
}
public class JavaTest001 {
public static void main(String[] args) {
Person per = new Student("张三",15,"北京大学");
System.out.println(per.getInfo());
}
}
其实抽象类中存在有构造方法也很好理解,毕竟抽象类中还有属性,所有的属性一定要在对象实例化的时候进行空间的开辟,对象实例化必须要使用构造方法。
额外话题:关于对象实例化。
对象的实例化操作实际上需要以下几个核心步骤:
- 进行类的加载;
- 进行类对象的空间开辟;
- 进行类对象中的属性初始化(构造方法);
abstract class A{
public A(){ //3.调用父类构造方法
this.print(); //4.调用被子类覆写过的方法
}
public abstract void print(); //抽象方法
}
class B extends A{
private int num = 100;
public B(int num){ //2.调用子类实例化对象
super(); //(3).隐含一行语句,实际要先调用父类构造方法
this.num = num; //7.为类中的属性初始化
}
@Override
public void print(){ //5.此时子类对象还没有被初始化
System.out.println(this.num); //6.内容为其对应数据类型的默认值
}
}
public class JavaTest001 {
public static void main(String[] args) {
new B(30); //1.实例化子类对象
}
}
结论:如果构造方法没有执行,那么对象中的属性一定都是其对应数据类型的默认值。
2.抽象类中允许不定义任何的抽象方法,但是此时抽象类对象依然无法进行直接实例化处理。
3.抽象类不能使用final进行声明,因为使用final定义的类不能有子类,而抽象类必须有子类;
- 抽象方法不能够使用private进行定义,应为抽象方法必须被覆写。
4.抽象类也分为内部抽象类和外部抽象类,内部抽象类中可以使用static定义,描述为外部抽象类。
而如果外部抽象类上使用static那么就是语法错误,可内部抽象类上允许使用static
.2.1抽象类的实际应用——模版设计模式
抽象类的最大特点在于强制规定了子类的实现结构,那么除了这一特点之外,抽象类更多更多的情况下还可以起到一个模板的作用,下面做一个简单的分析。
- 人 = 吃饭+睡觉+工作;
- 猪 = 吃饭+睡觉;
- 机器人 = 吃饭+工作。
那么现在假设有一个按钮控制(方法),一旦传入了某些指令之后就可以相应的处理。
**范例:**定义抽象的行为。
abstract class Action{ //描述的是一个抽象行为
public static final int EAT = 1;
public static final int SLEEP = 5;
public static final int WORK = 10;
public void command(int cmd){
switch(cmd){
case EAT:
this.eat();
break;
case SLEEP:
this.sleep();
break;
case WORK:
this.work();
break;
case EAT+SLEEP+WORK:
this.eat();
this.work();
this.sleep();
break;
}
}
//不确定具体的实现,但是行为应该定义好
public abstract void eat();
public abstract void sleep();
public abstract void work();
}
**范例:**定义各个行为的子类。
class Human extends Action{
public void eat(){
System.out.println("人吃熟食,干净的");
}
public void sleep(){
System.out.println("人困了就要睡觉");
}
public void work(){
System.out.println("人要努力拼搏!");
}
}
class Pig extends Action{
public void eat(){
System.out.println("猪用槽子吃。。");
}
public void sleep(){
System.out.println("躺土里直接睡。。。");
}
public void work(){}
}
class Robot extends Action{
public void eat(){
System.out.println("充电!!!");
}
public void sleep(){}
public void work(){
System.out.println("不停工作!!!");
}
}
public class JavaTest001 {
public static void main(String[] args) {
fun(new Human());
fun(new Pig());
fun(new Robot());
}
public static void fun(Action action){
action.command(Action.EAT+Action.WORK+Action.SLEEP);
}
}
通过此程序的定义结构可以清楚的发现一个问题:
- 抽象类在实际的使用过程之中会定义一些固化的模式,它只能接收几种特定的指令;
- 但是每种指令的具体实现由子类负责完成,父类只做了方法的约定;
最具有代表性的就是Servlet程序。
1.抽象类虽然定义了子类必须要做的事情,但是抽象类任然有单继承局限;
2.抽象类的使用必须要通过子类进行对象实例化处理。
.2、接口
如果要想约定子类的实现要求以及避免单继承的局限就需要使用接口。在以后的开发设计之中:接口优先。在一个操作即可以使用抽象类又可以使用接口的时候请优先考虑接口。
接口的基本概念:
接口就是一个抽象方法和全局常量的集合,在java中接口可以使用interface关键字来进行定义。
**范例:**定义一个接口
//接口前追加一个I(规范)
interface IMessage{
public static final String MSG = "www.qiao.com";
public abstract void print(); //抽象方法
}
如果子类要想使用接口,那么就必须利用implements关键字来实现接口,同时一个子类可以实现多个接口,也就是说可以利用接口来实现多继承的概念,对应接口的子类(如果不是抽象类)则必须覆写接口中的全部抽象方法随后可以利用子类对象的向上转型通过实例化子类来得到接口的实例化对象。
//接口前追加一个I(规范)
interface IMessage{
public static final String MSG = "www.qiao.com";
public abstract void print(); //抽象方法
}
interface INews{
public abstract String get();
}
class MessageImpl implements IMessage,INews{
public void print(){
System.out.println(IMessage.MSG);
}
public String get(){
return IMessage.MSG; //访问常量都建议加上类名称
}
}
public class JavaTest001 {
public static void main(String[] args) {
IMessage m = new MessageImpl(); //子类为父接口实例化
m.print(); //调用被子类所覆写过的方法
}
}
public class JavaTest001 {
public static void main(String[] args) {
INews m = new MessageImpl(); //子类为父接口实例化
//m表示的不是INews,而是MessageImpl。MessageImpl是IMessage的子类。
IMessage ms = (IMessage) m;
System.out.println(m.get());
}
}
当一个子类继承了多个接口之后,并且接口对象通过子类进行实例化,那么多个父接口之间是允许互相转换的。
接口的使用限制
- 接口一旦定义完成之后,就需要对其有一个核心的说明,那么首先需要说明的是:接口里面只允许存在有public权限,也就是说不管是属性还是方法其权限永恒都是public。
完整格式: | 简化格式 |
---|---|
interface INews{ public static final String MSG = “www.qiao.com”; public abstract String get(); } | interface INews{ String MSG = “www.qiao.com”; String get(); } |
- 在以后编写接口的时候,99%的接口里面只会提供有抽象方法,很少会在接口里面看见有许多的全局常量的。所有很多时候为了防止避免一些开发者出现混乱,所有接口的方法方法上往往都会加上public。
- 当一个子类需要实现接口又需要继承抽象类的时候,请先使用extends继承一个抽象类,而后再使用implements实现多个接口。
**范例:**让子类继承抽象类和实现接口。
interface INews{
public String get();
}
//可以在类上进行明确描述,在以后的开发中也经常出现以下的命名习惯。
abstract class AbstractMessage{
//只有接口中的abstract才可以省略,抽象类中不能省略。
public abstract void print();
}
class NewImpl extends AbstractMessage implements INews{
public String get(){
return "www.qiao.com";
}
public void print(){} //有方法体就称为覆写。
}
public class JavaTest001 {
public static void main(String[] args) {
INews news = new NewImpl();
System.out.println(news.get());
//NewImpl是抽象类和接口的共同子类。
AbstractMessage am = (AbstractMessage) news;
am.print();
}
}
- 一个抽象类可以使用implements实现多个接口,但是接口不能够去继承抽象类;
- 一个接口可以使用extends来继承多个父接口。
interface A{
public void printA();
}
interface B{
public void printB();
}
interface C extends A,B{ //接口多继承
public void printC();
}
class Impl implements C{
public void printA(){}
public void printB(){}
public void printC(){}
}
接口可以定义一系列的内部接口,包括:内部的普通类、内部抽象类、内部接口,其中使用static定义的内部接口就相当于一个外部接口。
interface A{
static interface B{ //使用static定义,描述了一个外部接口
public void printB();
}
}
class X implements A.B{ //实现内部接口
public void printB(){}
}
对应内部的结构不是首选,而且要想清楚接口的实际开发意义,需要大量的项目来验证。
接口的应用:定义标准。
对于接口在实际的开发之中有三大核心应用环境:
- 定义操作标准;
- 表示能力;
- 在分布式开发之中暴露远程服务方法。
现在要求描述出一个概念:电脑上可以使用任何的USB设备(U盘、打印机、分扇)。
**范例:**定义一个USB的标准。
interface UsB{
public void setup(); //安装USB的驱动
public void work(); //进行工作
}
**范例:**定义电脑类
class Computer{
public void plugin(USB usb){
usb.setup(); //安装
usb.work(); //工作
}
}
电脑在诞生的时候是不关注USB设备有那些的。
**范例:**定义USB的子类。
class Flash implements USB{
public void setup(){
System.out.println("安装U盘驱动");
}
public void work(){
System.out.println("进行数据传输");
}
}
class Print implements USB{
public void setup(){
System.out.println("安装打印机驱动");
}
public void work(){
System.out.println("进行文件打印");
}
}
**范例:**测试类。
public class JavaTest001 {
public static void main(String[] args) {
Computer com = new Computer();
com.plugin(new Flash());
com.plugin(new Print());
}
}
发现使用接口和对象多态性的概念结合之后,对于参数的统一更加明确了。而且可以发现接口是在类之上的设计抽象。
接口的设计模式——工厂设计模式(Factory、重点)
首先来看一个简单的程序范例:在进行类设计的时候,要求,首先需要有接口,而后接口要通过子类才可以进行对象的实例化处理。
**范例:**传统代码开发
interface IFruit{ //定义一个描述水果的操作
public void eat(); //吃水果
}
class Apple implements IFruit{
public void eat(){
System.out.println("削皮吃苹果");
}
}
public class JavaTest001 {
public static void main(String[] args) {
IFruit fruit = new Apple();
fruit.eat();
}
}
此时的程序实现的关键是:“IFruit fruit = new Apple();”,如果没有此语句,那么接口对象将无法进行实例化的操作处理。但是最大的败笔也在此。主方法是一个客户端,那么对于程序的修改不应该影响到客户端。
Java实现可移植性的关键是JVM,也就说所有的程序是在JVM上执行,而不同的操作系统中有匹配的JVM,相当于:程序——>JVM——>操作系统。
这个时候new是整个开发过程之中最大的耦(ou)合元凶,而我们在开发之中要想进行解耦合的关键就在于要引入一个第三方,所以这个类可以使用Factory来描述。
**范例:**通过Factory设计来描述
interface IFruit{ //定义一个描述水果的操作
public void eat(); //吃水果
}
class Factory{
//应该此时Factor产生实例化对象没有意义(为啥用static)
public static IFruit getInstance(String className){
if("apple".equals(className)){
return new Apple();
}
if("orange".equals(className)){
return new Orange();
}
return null;
}
}
class Apple implements IFruit{
public void eat(){
System.out.println("削皮吃苹果");
}
}
class Orange implements IFruit{
public void eat(){
System.out.println("剥皮吃橘子");
}
}
public class JavaTest001 {
public static void main(String[] args) {
if(args.length != 1){ //没有传递一个参数
System.out.println("对不起,程序执行错误,正确的格式:java TestDemo 类名称");
System.exit(1); //退出程序执行
}
IFruit fruit = Factory.getInstance(args[0]);
fruit.eat();
}
}
当更换使用的IFruits子类的时候主方法没有任何的变化就可以实现了子类的变更,这样的设计就称为工厂设计模式。
**总结:**以后编写的接口如果要想取得接口的实例化对象,第一反映:写工厂类。
接口的设计模式——代理设计模式(Proxy)
所谓的代理严格来讲就是两个子类共同实现一个接口,其中一个子类负责真实的业务实现,而另外的子类负责辅助真实业务主题的操作。
**范例:**实现代理设计
interface ISuject{
public void save(); //核心功能是救人
}
class RealSubject implements ISuject{
public void save(){
System.out.println("英勇的制止了于先生的不法侵害。");
}
}
class ProxySubject implements ISuject{ //代理实现
private ISuject suject; //真正的操作业务
//在创建代理类对象的时候必须设置要代理的真实主题
public ProxySubject(ISuject suject){
this.suject = suject;
}
public void broke(){
System.out.println("破门而入!");
}
public void get(){
System.out.println("得到见义勇为奖!");
}
public void save(){ //接口子类一定要实现抽象方法
this.broke(); //真实操作前的准备
this.suject.save(); //调用真实的业务
this.get(); //操作后的收尾
}
}
public class JavaTest001 {
public static void main(String[] args) {
ISuject sub = new ProxySubject(new RealSubject());
//通过代理类对象发出,利用代理类来实现真实业务调用
sub.save(); //救人的核心操作
}
}
对于初次接触代理设计模式来讲有一些抽象。
代理本质:所有的真实业务操作都会有一个与之辅助的功能类共同完成。
抽象类与接口的区边
抽象类和接口都属于常用的类结构设计,在开发之中都会出现,不过如果按照优先选择来讲,接口一定要比抽象类更方便。
概念上对比:
No | 区别点 | 抽象类 | 接口 |
---|---|---|---|
1 | 关键字 | abstract class 类名称{} | interface 接口名称{} |
2 | 结构组成 | 抽象方法、普通方法、全局常量、全局变量、属性、构造方法 | 抽象方法和全局常量 |
3 | 权限 | 可以使用各种权限 | 只能使用public权限 |
4 | 子类使用 | 子类利用extends关键字来继承抽象类 | 子类使用implements关键字来实现接口 |
5 | 关系 | 一个抽象类可以实现若干个接口 | 一个接口不能够继承抽象类,但是可以使用extends来继承多个父接口 |
6 | 子类限制 | 一个子类只能够继承一个抽象类 | 一个子类可以实现多个接口 |
除了单继承的局限之外,实际上使用抽象类和接口都是类似的。但是在实际的开发之中,抽象类的设计要比接口复杂。
对于现在已经学习的概念发现结构体很多:类、对象、抽象类、接口,那么这几者的具体关系可以通过如下的一张图来描述。