接口
接口的使用
1.使用interface来定义
2.在Java中,接口和类是两个并列的结构
3.如何定义接口:定义接口中的成员
①JDK7以及以前:只能定义全局常量和抽象方法
全局常量:public static final ,书写时可以省略
抽象方法:public abstract,书写时可以省略
②JDK8中:除了定义全局常量和抽方法之外,还可以定义静态方法、默认方法
4.接口中不能定义构造器
接口不可以实例化
5.Java开发中,接口通过让类去实现(implements)的方式来使用
如果实现类覆盖了接口中所有的抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法则此实现类仍为一个抽象类
6.Java类可以实现多个接口 —>弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD,EE
7.接口与接口之间可以继承,且可以多继承
8.接口的具体使用,体现多态性,实际上可以看做是一种规范
抽象类与接口的区别
抽象类(abstract class):
使用abstract修饰符修饰的类。
实际点来说,一个抽象类不能实例化,因为“没有包含足够多的信息来描述一个具体的对象”。但仍然拥有普通类一样的定义。依然可以在类的实体(直白点就是能在{}里面)定义成员变量,成员方法,构造方法等。
抽象方法:只声明,不实现。具体的实现由继承它的子类来实现。实际点就是:被abstract修饰的方法,只有方法名没有方法实现,具体的实现要由子类实现。方法名后面直接跟一个分号,而不是花括号。例如:public abstract int A();
一个类中含有抽象方法(被abstract修饰),那么这个类必须被声明为抽象类(被abstract修饰)。
接口(interface):
定义:接口在java中是一个抽象类型,是抽象方法的集合。一个类通过继承接口的方式,从而继承接口的抽象方法。类描述了属性和方法,而接口只包含方法(未实现的方法)。
接口和抽象类一样不能被实例化,因为不是类。但是接口可以被实现(使用 implements 关键字)。实现某个接口的类必须在类中实现该接口的全部方法。虽然接口内的方法都是抽象的(和抽象方法很像,没有实现)但是不需要abstract关键字。
接口中没有构造方法(因为接口不是类)
接口中的方法必须是抽象的(不能实现)
接口中除了static、final变量,不能有其他变量
接口支持多继承(一个类可以实现多个接口)
接口的应用:代理模式
①代理设计就是为其他对象提供一种代理以控制对这个对象的访问
②应用场景
- 安全代理:屏蔽对真实角色的直接访问
- 远程代理:通过代理类处理远程方法调用(RMI)
- 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象
③分类
Ⅰ.静态代理(静态定义代理类)
Ⅱ.动态代理(动态生成代理类)
JDK自带的动态代理,需要反射等知识
五、接口的应用:工厂模式
实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的
interface IClassName {
public String getClassName();
}
public class day3 {
public static void main(String[] args) {
IClassName ica= new Company();
System.out.println(ica.getClassName());
}
}
class Company implements IClassName{
@Override
public String getClassName() {
return "Company";
}
}
工厂:专门用来造对象
分类
①无工厂模式
②简单工厂模式(静态工厂模式)
用来生产同一等级结构中的任意产品,工厂类一般使用静态方法,通过接收参数的不同来返回不同的实例对象
缺点:对于增加新产品,不修改代码则无法扩展。违反了开闭原则(对扩展开放,对修改封闭)
③工厂方法模式
为了避免简单工厂模式的缺点,不完全满足OCP(对扩展开放,对修改封闭)。
用来生产同一等级结构中的固定产品
与简单工厂模式的区别:简单工厂模式只有一个(对于一个项目或者一个独立的模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类
④抽象工厂模式
与工厂方法模式的区别:需要创建对象的复杂程度
用意:用来生产不同产品族的全部产品
是最抽象、最具有一般性的
使用时需要满足的条件:
系统中有多个产品族,而系统一次只可能消费其中一族产品
同属于同一个产品族的产品一起使用
实例 1:绘图
/*
* 绘图:工厂模式
*/
interface IGrapjical{//定义绘图标准
public void paint();//绘图
}
class Circular implements IGrapjical{
private double radius;
public Circular(double radius){
this.radius=radius;
}
public void paint(){
System.out.println("以半径为"+this.radius+"绘制圆形");
}
}
class Triangle implements IGrapjical{//绘制三角形
private Point[] x; //第一条边
private Point[] y;//第二条边
private Point[] z;//第三条边
public Triangle(Point[] x,Point[] y,Point[] z){
this.x=x;
this.y=y;
this.z=z;
}
@Override
public void paint() {
System.out.println("绘制第一条边开始坐标:"+this.x[0].getX()+","+this.x[0].getY()+",结束坐标:"+this.x[1].getX()+","+this.x[1].getY());
System.out.println("绘制第一条边开始坐标:"+this.y[0].getX()+","+this.y[0].getY()+",结束坐标:"+this.y[1].getX()+","+this.y[1].getY());
System.out.println("绘制第一条边开始坐标:"+this.z[0].getX()+","+this.z[0].getY()+",结束坐标:"+this.z[1].getX()+","+this.z[1].getY());
}
}
class Point{
private double x;
private double y;
public Point(double x,double y){
this.x=x;
this.y=y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
}
class Factory{
public static IGrapjical getIntance(String className,double ... args){
if("triangle".equalsIgnoreCase(className)){
return new Triangle(
new Point[] {
new Point(args[0],args[1]),
new Point(args[2],args[3]),
},
new Point[]{
new Point(args[4],args[5]),
new Point(args[6],args[7]),
},
new Point[]{
new Point(args[8],args[9]),
new Point(args[10],args[11])}
);
}else if("circular".equalsIgnoreCase(className)){
return new Circular(args[0]);
}else {
return null;
}
}
}
public class day3 {
public static void main(String[] args) {
IGrapjical iga= Factory.getIntance("triangle",1.1,2.2,3.3,4.4,11.11,22.22,33.33,44.44,111.111,222.222,333.333,444.444);
iga.paint();
IGrapjical igb=Factory.getIntance("circular",88.11);
igb.paint();
}
}
/*
* 图形设计
* */
*abstract class ShrapAbs{
public abstract double area();
public abstract double perimeter();
}
class Circular extends ShrapAbs{
private double radius;
public Circular(double radius){
this.radius=radius;
}
public double area(){
return 3.415926*this.radius*this.radius;
}
public double perimeter(){
return 2*3.1415926*this.radius;
}
}
class Rectangle extends ShrapAbs{
private double length;
private double width;
public Rectangle(double length,double width){
this.length=length;
this.width=width;
}
@Override
public double area() {
return length*width;
}
@Override
public double perimeter() {
return 2*length+2*width;
}
}
class Factory{
public static ShrapAbs getInstance(String className,double ... args){
if ("Circular".equalsIgnoreCase(className)){
return new Circular(args[0]);
}else if("Rectangle".equalsIgnoreCase(className)){
return new Rectangle(args[0],args[1]);
}else {
return null;
}
}
}
public class day3 {
public static void main(String[] args) {
ShrapAbs saa=Factory.getInstance("Circular",1.1);
ShrapAbs sab=Factory.getInstance("Rectangle",1.1,2.2);
System.out.println("圆形面积"+saa.area()+"圆形周长"+saa.perimeter());
System.out.println("矩形面积"+sab.area()+"矩形周长"+sab.perimeter());
}
}
泛型
主要为了解决ClassCastExceotion的问题,再进行对象的向下转型永远可能存在有安全隐患,java希望通过泛型来慢慢解决此类问题。
package com.test;
class Point {
private Object x ;
private Object y ;
public void setX(Object x) {
this.x = x ;
}
public void setY(Object y) {
this.y = y ;
}
public Object getX() {
return this.x ;
}
public Object getY() {
return this.y ;
}
}
public class JavaDemo { // 主类
public static void main(String args[]) { // 主方法
Point point = new Point() ;
point.setX(10) ; // 自动装箱&向上转型
point.setY("北纬20度") ; // 自动装箱&向上转型
int x = (Integer) point.getX() ; // 向下转型 & 自动拆箱
int y = (Integer) point.getY() ; // 向下转型 & 自动拆箱
System.out.println("x = " + x + "、y = " + y) ;
}
}
泛型问题引出
Object可以接受所有的数据类型,但是正因如此,程序会出现安全隐患
class Point<T> { // T表示Type
private T x ;
private T y ;
public void setX(T x) {
this.x = x ;
}
public void setY(T y) {
this.y = y ;
}
public T getX() {
return this.x ;
}
public T getY() {
return this.y ;
}
}
public class JavaDemo { // 主类
public static void main(String args[]) { // 主方法
Point<Integer> pointA = new Point<Integer>() ;
Point<String> pointB = new Point<String>() ;
pointA.setX(10) ;
pointA.setY(20) ;
System.out.println("x = " + pointA.getX() + "、y = " + pointA.getY()) ;
pointB.setX("东30");
pointB.setY("西30");
System.out.println("x = " + pointB.getX() + "、y = " + pointB.getY()) ;
}
}
此时,程序设置了泛型"T",
在main方法中实例化对象pointA (“Point pointA = new Point()”)的时候进行了Integer类型的定义
实例化对象pointB (“Point pointB = new Point()”)的时候进行了String类型的定义
多泛型变量定义
1.多泛型变量定义
我们不止可以在类中设置一个泛型变量T,还可以声明多个泛型变量,写法如下:
public class ObjClass<T,U>
也就是在原来的T后面用逗号隔开,写上其它的任意大写字母即可,如果还有多个,依然使用逗号分隔开即可,则我们前面定义的泛型类就会变成下面这样:
public class ObjClass<T,U> {
private T x ;
private U y ;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public U getY() {
return y;
}
public void setY(U y) {
this.y = y;
}
}
ObjClass<String,Integer> stringClass = new ObjClass<String,Integer>();
stringClass.setX("haha");
stringClass.setY(100);
使用通配符"?"来解决问题
package com.test;
class Message<T> {
private T info ;
public void setInfo(T info) {
this.info = info ;
}
public T getInfo() {
return this.info ;
}
}
public class JavaDemo { // 主类
public static void main(String args[]) { // 主方法
Message<String> msg = new Message<String>() ;
msg.setInfo("今天好热") ;
fun(msg) ;
Message<Integer> ms = new Message<Integer>() ;
ms.setInfo(10) ;
fun(ms) ;
}
public static void fun(Message<?> temp) {
System.out.println(temp.getInfo()) ;
}
}
在通配符"?“的基础上,还提供两类小的通配符:
? extends 类:设置泛型的上限
例如:”? extends Number":表示该泛型类型只允许设置"Number"或者"Number"的子类
? super 类:设置泛型的下限
例如:"? super String":表示该泛型类型只允许使用"String"或"String"的父类
泛型接口:
在子类之中继续设置泛型定义
interface IMessage<T> {
public String test(T t) ;
}
class MessageImpl<S> implements IMessage<S> {
public String test(S t) {
return "【测试】" + t;
}
}
public class JavaDemo { // 主类
public static void main(String args[]) {
IMessage<String> msg = new MessageImpl<String>() ;
System.out.println(msg.test("测试"));
}
在子类实现父接口的时候直接定义出具体泛型类型
interface IMessage<T> {
public String test(T t) ;
}
class MessageImpl implements IMessage<String> {
public String test(String t) {
return "【测试】" + t;
}
}
public class JavaDemo { // 主类
public static void main(String args[]) {
IMessage<String> msg = new MessageImpl() ;
System.out.println(msg.test("测试"));
}
}
泛型方法
如果将泛型标记写在了方法上,那么这样的方法就被称为泛型方法,如果一个类上没有定义泛型,那么也可以使用泛型方法:
public class JavaDemo { // 主类
public static void main(String args[]) { // 主方法
Double [] result = init(1.1,2.2,3.3) ; // 由外部设置泛型类型
for (double temp : result) {
System.out.print(temp + "、") ;
}
}
public static <T> T[] init(T ... args) {
return args ;
}
}
泛型的扩展
单例设计模型
/*
单例设计模型:饿汉式
*/
class Singleton{
private static final Singleton INSTANCE =new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE
}
public void print(){
System.out.println("www.xyq.cn");
}
}
public class day3 {
public static void main(String[] args) {
Singleton instance =null;
instance =Singleton.getInstance();
instance.print();
}
}
//懒汉式
class Singleton{
private static Singleton instance;
private Singleton(){}//构造方法私有化
public static Singleton getInstance(){
if(instance==null){//第一次实例化
instance=new Singleton();
}
return instance;
}
public void print(){
System.out.println("www.xyq.cn");
}
}
public class day3 {
public static void main(String[] args) {
Singleton instance =null;
instance =Singleton.getInstance();
instance.print();
}
}
多例设计模型比如:男 女 (不可能再多了)
class Color{
private static final Color RED =new Color("红色");
private static final Color GREEN =new Color("绿色");
private static final Color BLUE=new Color("蓝色");
private String title;
private Color(String title){ //构造方法私有化
this.title=title;
}
public static Color getInstance(int color){
switch(color){
case 1:return RED;
case 2:return GREEN;
case 3:return BLUE;
default:return null;
}
}
public String toString(){
return this.title;
}
}
public class day3 {
public static void main(String[] args) {
Color c=Color.getInstance(3);
System.out.println(c);
}
}
枚举
实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum类
enum Color{
RED,GREEN,BLUE;
}
public class day3 {
public static void main(String[] args) {
Color c=Color.RED;
System.out.println(c);
}
}
public enum Day3 {
MONDAY("星期一"),
TUESDAY("星期二"),
WEDNESDAY("星期三"),
THURSDAY("星期四"),
FRIDAY("星期五"),
SATURDAY("星期六"),
SUNDAY("星期日");//记住要用分号结束
private String desc;//中文描述
private Day2(String desc){
this.desc=desc;
}
public String getDesc(){
return desc;
}
public static void main(String[] args){
for (Day2 day:Day2.values()) {
System.out.println("name:"+day.name()+
",desc:"+day.getDesc());
}
}
枚举与switch
enum Color {GREEN,RED,BLUE}
public class EnumDemo4 {
public static void printName(Color color){
switch (color){
case BLUE: //无需使用Color进行引用
System.out.println("蓝色");
break;
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
}
}
public static void main(String[] args){
printName(Color.BLUE);
printName(Color.RED);
printName(Color.GREEN);
}
枚举的单例设计模式的引用
单例模式
实际应用中,线程池、缓存、日志对象、对话框对象常被设计成单例,总之,选择单例模式就是为了避免不一致状态,下面我们将会简单说明单例模式的几种主要编写方式,从而对比出使用枚举实现单例模式的优点。首先看看饿汉式的单例模式:
public class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry() {
}
public static SingletonHungry getInstance() {
return instance;
}
}
/**
* Created by wuzejian on 2017/5/9..
* 懒汉式单例模式(适合多线程安全)
*/
public class SingletonLazy {
private static volatile SingletonLazy instance;
private SingletonLazy() {
}
public static synchronized SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
public class Singleton {
private static volatile Singleton singleton = null;
private Singleton(){}
public static Singleton getSingleton(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
这种是“双重检查锁”,主要在getSingleton()方法中,进行两次null检查。