/* 2. 使用static修饰属性,静态变量
* 2.1 属性:
* 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性,当修改一个对象的非静态属性时,不会导致其对象中的相同属性的修改
* 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量
* 2.2 static修饰属性的其他说明
* (1)静态变量随着类的加载而加载(实例变量随着类的创建而创建)
* (2)静态变量早于对象的创建
* (3)由于类只会加载一次,所以静态变量在内存怒中也只会存在一份,存在于方法区的静态域中
* (4) 类变量 实例变量
* 类 yes no
* 对象 yes yes
* static举例:System.out.println()的out ; Math.PI
* System.class下
* public static final PrintStream out = null;
* PrintStream.class下
* public void println() {newLine();}
* /
/* 4. 使用static修饰方法
* ① 随着类的加载而加载,可以通过“类.静态方法”的使用进行调用
* ② 静态方法 非静态方法
* 类 yes no
* 对象 yes yes
* ③ 静态方法中,只能调用静态的方法或者属性
* 非静态方法中,可以调用非静态的方法或属性,也可以调用静态的方法或者属性
*/
* 5. static注意点
* 在静态的方法中, 不能使用this关键字,super关键字 (对象的父类,对象都没有,怎么用?)
/* 6.1 开发中如何确定一个属性是否要声明为static?
* * 属性可以被多个对象所共享,不会随着对象的不同而不同
* * 类中的常量,也常常声明为static
*/
/* 6.2 开发中如何确定一个方法是否要声明为static?
* 操作静态属性的方法,通常设置为static的。(方法权限和属性权限一般一致)
* 工具类中的方法,习惯上声明为static的。好处:不必再找对象
比如Math, Arrays, Collections
工具类中的方法一般都有形参,主要体会在做的事情,而不在于谁做的,工具类是帮我们做事情的
*/
// 8. 自动生城的toString()只会输出私有的 static不会输出
Arrays ;Math ; Collection
等工具类总共23种
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式是大量的实践中总结和理论化之后优选的代码结构,编程风格,以及解决问题的思考方式。设计模式免去我们在思考和摸索。
所谓类的单例设计模式,就是采取一定的方法保证整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类再一个虚拟中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类的内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
单例模式优点:由于单例模式只生成一个实例,减少了系统性能开销,当一个对象产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在英勇启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
实现方式
饿汉式
package com.shc.java2;
/*
* 单例设计模式
* 1. 所谓类的单例设计模式,就是采取一定的方法报这个在整个软件系统中,对某个类只能存在一个对象实例
*
* 2. 如何实现?
* 懒汉式 vs 饿汉式
* 懒汉式:用的时候才造
* 饿汉式:加载的时候就造了
*
* 3. 区分饿汉式和懒汉式
* 饿汉式:
* 坏处:对象加载时间过长(对象一上来就有了)
* 好处:饿汉式是线程安全的
* 懒汉式:
* 好处:延迟对象的创建
* 目前写法坏处:线程不安全 -->到多线程内容时,再修改
*/
public class SingletonTest1 {
public static void main(String[] args) {
// Bank bank1 = new Bank(); error private构造器
Bank b1 = Bank.getInstance();
Bank b2 = Bank.getInstance();
System.out.println(b1.equals(b2));//true 地址相同 二者管理的是同一个对象
}
}
class Bank{
//1.私有化类的构造器(避免在类的外部使用构造器产生对象)
private Bank() {
}
//2. 内部创建类的对象
private static Bank instance = new Bank();
//3. 提供公共方法,返回类的对象
//设置为static 为了让外部在没有该类的对象的情况下就可以调用该类中的方法来获得对象
public static Bank getInstance() {
return instance;
}
}
懒汉式
package com.shc.java2;
/*
* 懒汉式 :不用就不造 需要用了才造
*/
public class SingletonTest {
public static void main(String[] args) {
Order order1 = Order.getInstance();
Order order2 = Order.getInstance();
System.out.println(order1.equals(order2));//true
}
}
class Order{
//1.私有化构造器
private Order(){
super();
}
//2.声明当前类对象,没有初始化
private static Order instance = null;//此对象也必须声明为static的
//3.声明public,static的返回当前类对象的方法
public static Order getInstance() {
if(instance==null) instance = new Order(); //防止重复产生对象
return instance;
}
}
java.lang.Runtime
(饿汉式)
public class Runtime {
private static final Runtime currentRuntime = new Runtime();
private static Version version;
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class {@code Runtime} are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the {@code Runtime} object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don‘t let anyone else instantiate this class */
private Runtime() {}
应用场景
网站的计数器,一般也是单例模式实现,否则难以同步。
应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志 文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库 资源。
项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置 文件数据,都生成一个对象去读取。 ?
Application 也是单例的典型应用
? - 应用程序运行起来就有一个进程,在应用程序执行的进行中,只会存在一个Appliaction
Windows的Task Manager (任务管理器)就是很典型的单例模式
Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程 中,回收站一直维护着仅有的一个实例
/*
* main()方法的使用说明:
* 1. main()方法作为程序的入口
* 2. main()也可是一个普通的静态方法
* 3. main()方法也可以作为与控制台交互的一种方式(之前,使用Scanner)
* 4. eclipse交互:run as --> Run configuration -->目标字节码文件 -->Argument. 再填入字符串数组,以空格为分隔,有无""均可
* 5. 命令行交互: cmd--> javac MainDemo.java -->java MainDemo 这是不传参数 ---> java MainDemo "55" 99 .. 这是传参数
*/
命令行如何将控制台获取的数据传给形参:String args[]
运行时:java 类名"Tom""Jerry""123""true"
syso(args[0]); //Tom
syso(args[3]); //true
syso(args[4]); //Exception
package com.shc.java2;
public class MainTest {
//main()中不可以直接调本类的非static方法和属性,需要new对象再通过对象调用
//因为main()方法是static的
//public:方法权限
//调main()方法必须得有当前类来调,因为还没有产生对象,产生独对象得在main()里.所以是main()是static的
public static void main(String[] args) {//入口
Main.main(new String[10]);
// show();
hh();
}
public void show() {}
public static void hh() {}
}
class Main{
public static void main(String[] args) {
for(int i=0;i<args.length;i++) {
args[i]="args_"+i;
System.out.println(args[i]);
}
}
}
args_0
args_1
args_2
args_3
args_4
args_5
args_6
args_7
args_8
args_9
public static void main(String[] args){//方法体}
/*权限修饰符*/
private 缺省 protected public -->封装性
/*修饰符*/
static \ final \ abstract \ native 可以用来修饰方法
/*方法名*/
//方法名:需要满足标识符命名规则,规范
/*形参列表*/
//重载vs重写 ; 参数的值传递机制 ; 对象多态性
package com.shc.java3;
/*
* 类的成员之四:代码块(或初始化块)
* 1. 代码块的作用:用来初始化类,对象
* 2. 代码块如果有修饰的话,只能使用static
* 3. 分类:静态代码块 vs 非静态代码块
*
* 4. 静态代码块
* 内部可以有输出语句
* 随着类的加载而执行,而且只执行一次
* 作用:初始化类的信息
* 如果一个类中定义了多个静态代码块,则按照声明的先手顺序执行
* 静态代码块的执行优先于非静态代码块的执行
* 静态代码块内只能调用静态的属性,静态方法,不能调用非静态的结构
*
* 5. 非静态代码块
* 内部可以有输出语句
* 随着对象的创建而执行,每个对象创建都会执行一次
* 作用:可以在创建对象时,对对象的属性进行初始化
* 如果一个类中定义了多个非静态代码块,则按照声明的先手顺序执行
* 静态代码块内既能调用静态的属性,静态方法,也能调用非静态的结构
*
* 对属性可以赋值的位置
* ①默认初始化
* ②显式初始化 / * ④在代码块中赋值 代码块先于构造器执行 显式初始化与代码块谁写在前面先执行谁
* ③构造器中初始化
* ⑤getter() setter()
*
* 6. 静态代码块的使用情景
*
*/
public class BlockTest {
public static void main(String[] args) {
//啥语句都没有时不会再加载person类
String desc = Person.desc; //只有这句时输出 static block-1 static block-2
Person p = new Person(); //static block-1, static block-2, not static block-1, not static block-2
Person p1 = new Person(); //static block-1, static block-2, not static block-1, not static block-2, not static block-1, not static block-2
// System.out.println(p.age);
///person.hh();
}
}
class Person{
String name;
int age;
static String desc = "我是一个人";
public Person() {}
//构造器
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
//static代码块
//随着类的加载而执行
static{
System.out.println("static block-1");
desc = "我爱学习";
}
static{
System.out.println("static block-2");
desc = "我爱学习";
}
//非static代码块
//随着对象的创建而执行
{
System.out.println("not static block-1");
age = 1;
}
{
System.out.println("not static block-2");
age = 1;
}
//方法
public void eat() {
System.out.println("吃饭");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
//static方法随着类的加载而加载 但是没有执行
public static void hh() {
System.out.println("hh");
}
}
package com.shc.java4;
import java.lang.constant.Constable;
import java.lang.constant.ConstantDesc;
//import jdk.internal.HotSpotIntrinsicCandidate;
/*
* final:最终的
* 1. final 可以用来修饰结构,类,方法,变量
* 2. final 用来修是一个类:此类不能被其它类继承
* 比如:String类,System类,StringBuffer类
* 为什么String是final? 因为该有的方法都写好了,基本上以后不会在继承这个类去扩充了
* public final class String implements java.io.Serializable, Comparable<String>, CharSequence,
Constable, ConstantDesc {
* 3. final 用来修饰方法:该方法不可以被重写
* 比如: Object类中的getClass()
* @HotSpotIntrinsicCandidate
public final native Class<?> getClass();
native:本地的
为什么这个方法没有写具体的方法体?
因为标名为natvie 代表接下来要调用底层的C/C++代码 这部分不对外开放
* 4. final 修饰变量,此时的变量称为常量
* 4.1 final修饰属性,可以考虑赋值的位置有:
* 显式初始化 final int LEFT=10;
* 代码块中赋值
* 构造器中初始化
*
* 如何选择?
* 如果造多个对象,这些对象的常量属性还一样.比如都设成0 那么就可以直接显示初始化.
* 如果要赋的不简单的一个值,需要调方法,方法还抛异常,那就只能在代码块中做
* 如果每个对象的常量的值不一样,那么就在构造器中进行
* 4.2 final修饰局部变量
* 尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参,一旦传入以后,就只能在方法体内使用此形参,但不能进行重新赋值
*
* static final 用来修饰属性: 即为全局常量
* (一起修饰方法较少,主要是修饰属性)
*
*Wrong!! final 参数只能使用不能修改
* public class Something {
public int addOne(final int x) {
return ++x;
// return x + 1;
}
}
Yes! 引用变量o不再管理其他对象即可
* public class Something {
public static void main(String[] args) {
Other o = new Other();
new Something().addOne(o);
}
public void addOne(final Other o) {
// o = new Other();
o.i++;
}
}
class Other {
public int i;
}
*
*/
public class FinalTest {
//1. 显式初始化
final int LEFT = 0;
final int RIGHT ;
final int DOWN;
// final int UP;
//2. 代码块中赋值
{
RIGHT = 1;
}
//3.构造器中初始化
public FinalTest() {
DOWN = 0;
}
//如果一个常量没有显式初始化也没有在代码块中初始化,那么就必须在构造器中初始化赋值
public FinalTest(int n) {
DOWN = n;
}
//
public void show(final int num) {
// num+=10;编译error
}
// public void setUP(int up) {
// this.UP = up;
// }
//
}
final class FinalA{
}
//class A{
// public final void show() {}
//}
//
//class B extends A{
// public void show() {}
//}
//Multiple markers at this line
//- Cannot override the final method
// from A
//- overrides com.shc.java4.A.show
//class B extends FinalA{
//
//}
//class C extends String{
//
//}
class Bank{
//1.私有化类的构造器(避免在类的外部使用构造器产生对象)
private Bank(){
}
//2.内部创建类的对象
private static Bank instance = new Bank();
//3.提供公共方法,返回类的对象
//设置为static 为了让外部再没有该类的对象的情况下就可以调用该类中的方法来获得对象
public static Bank getInstance(){
return instance;
}
}
或者
class Bank{
private Bank(){
}
//注意是public final
//在需要要这个类的对象时直接Bank bank1 = Bank.instance; 不需要getInstance()方法
public static final Bank instance = new Bank();
}
class Bank{
//1.私有化类的构造器
private Bank(){
}
//2.内部创建类的对象
private static Bank instance = null;
//3. 提供公共方法 返回类的对象
public static Bank getInstance(){
return instance==null? instance=new Bank():instance;
或者
if(instance==null) instance = new Bank();
return instance;
}
}
类的属性赋值的位置有哪些,先后顺序为何?
abstract修饰类:抽象类
abstract修饰方法:抽象方法
举例
举例1:
举例2:IO流中涉及到的抽象类:InputStream/OutputStream/Reader/Writer
在其内部定义了抽象的read(),write()方法public abstract int read() throws IOException;
。因为读写的时候情况很多,不知道具体情况,所以写成抽象。
题目要求
编写工资系统,实现不同类型员工(多态)的按月发放工资。
如果当月出现某个 Employee对象的生日,则将该雇员的工资增加100元。
实验说明:
(1)定义一个Employee类,该类包含: private成员变量name,number,birthday,其中birthday 为MyDate类的对象; abstract方法earnings(); toString()方法输出对象的name,number和birthday。
(2)MyDate类包含: private成员变量year,month,day ; toDateString()方法返回日期对应的字符串:xxxx年xx月xx日
(3)定义SalariedEmployee类继承Employee类,实现按月计算资的员工处理。该类包括:private成员变量monthlySalary; 实现父类的抽象方法earnings(),该方法返回monthlySalary值;toString()方法输 出员工类型信息及员工的name,number,birthday。 (4)参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的 员工处理。该类包括: private成员变量wage和hour; 实现父类的抽象方法earnings(),该方法返回wage*hour值; toString()方法输出员工类型信息及员工的name,number,birthday。
(5)定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各 类雇员对象的引用。利用循环结构遍历数组元素,输出各个对象的类 型,name,number,birthday,以及该对象生日。当键盘输入本月月份值时,如果本 月是某个Employee对象的生日,还要输出增加工资信息。
提示:
//定义People类型的数组People c1[]=new People[10];
//数组元素赋值 c1[0]=new People("John","0001",20); c1[1]=new People("Bob","0002",19);
//若People有两个子类Student和Officer,则数组元素赋值时,可以使父类类型的数组元素指向子类。
c1[0]=new Student("John","0001",20,85.0); c1[1]=new Officer("Bob","0002",19,90.5);
package com.shc.exer2;
/*
* 实验说明:
(1)定义一个Employee类,该类包含:
private成员变量name,number,birthday,其中birthday 为MyDate类的对象;
abstract方法earnings();
toString()方法输出对象的name,number和birthday。
*/
public abstract class Employee {
private String name;
private int number;
private MyDate birthday;
// public Employee() {} //如果子类构造器时调用这个构造器的话,那么子类就无法对name,number,birthday进行初始化
public Employee(String name, int number, MyDate birthday) {
super();
this.name = name;
this.number = number;
this.birthday = birthday;
}
public abstract double earning();
@Override
//toString()是返回字符串 不是自己输出字符串
public String toString() {
//因为这个方法一定是子类调用,所以没必要写那个Employee类的名字了
return " [name=" + name + ", number=" + number + ", birthday=" + "]"+birthday.toDateString();//注意这里调用了MyDate类的birthday的toString方法
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
// @Override
// public String toString() {
// return " [name="+name+", number="+number+", birthday="+birthday;
// }
}
package com.shc.exer2;
/*
* 2)MyDate类包含:
private成员变量year,month,day ;
toDateString()方法返回日期对应的字符串:xxxx年xx月xx日
*/
public class MyDate {
private int year;
private int month;
private int day;
public String toDateString() {
return year+"年"+month+"月"+day+"日";
}
public MyDate(int year, int month, int day) {
super();
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
}
package com.shc.exer2;
/*
* (3)定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处理。
* 该类包括:
* private成员变量monthlySalary;
* 实现父类的抽象方法earnings(),该方法返回monthlySalary值;
* toString()方法输出员工类型信息及员工的name,number,birthday
*/
public class SalariedEmployee extends Employee{
private double monthlySalary;
// public SalariedEmployee() {}
public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) {
super(name, number, birthday);
this.monthlySalary = monthlySalary;
}
@Override
public double earning() {
// TODO Auto-generated method stub
return monthlySalary;
}
public String toString() {
return "SalariedEmployee: "+super.toString()+"]";
}
public double getMonthlySalary() {
return monthlySalary;
}
public void setMonthlySalary(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
}
package com.shc.exer2;
/*
* 4)参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的
员工处理。该类包括:
private成员变量wage和hour;
实现父类的抽象方法earnings(),该方法返回wage*hour值;
toString()方法输出员工类型信息及员工的name,number,birthday。
*/
public class HourlyEmployee extends Employee{
private double wage;
private int hour;
public HourlyEmployee(String name, int number, MyDate birthday) {
super(name, number, birthday);
}
public HourlyEmployee(String name, int number, MyDate birthday, double wage, int hour) {
super(name, number, birthday);
this.wage = wage;
this.hour = hour;
}
@Override
public double earning() {
return wage*hour;
}
@Override
public String toString() {
return "HourlyEmployee: "+super.toString()+"]";
}
public double getWage() {
return wage;
}
public void setWage(double wage) {
this.wage = wage;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
}
package com.shc.exer2;
import java.util.Calendar;
import java.util.Scanner;
/*
* 定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各类雇员对象的引用。
* 利用循环结构遍历数组元素,输出各个对象的类型,name,number,birthday。
* 当键盘输入本月月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息。
payroll
n. (公司员工的)工资名单; (公司的)工资总支出;
[例句]We have 500 people on the payroll.
我们在编员工有500人。
*/
public class PayrollSystem {
public static void main(String[] args) {
// TODO Auto-generated method stub
//方式一
// Scanner in = new Scanner(System.in);//读入
// System.out.println("请输入当月月份");
// int month = in.nextInt();
//方式二 日期相关API
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH);//获取当前日期
//注意如果是用日历API的话,是从0月开始到11月
//所以比较的时候要month+1
Employee[] employees = new Employee[2];
employees[0]=new SalariedEmployee("shc", 201, new MyDate(2002, 4, 20), 100000);
employees[1]=new HourlyEmployee("ywt", 202, new MyDate(2001,9,9), 60, 240);
for(int i=0;i<employees.length;i++) {
System.out.println(employees[i]);
double salary = employees[i].earning();
System.out.println("月工资为"+salary);
if(month == employees[i].getBirthday().getMonth()) {
System.out.println("生日快乐");
}
}
}
}
请输入当月月份
4
SalariedEmployee: [name=shc, number=201, birthday=]2002年4月20日]
月工资为100000.0
生日快可乐
HourlyEmployee: [name=ywt, number=202, birthday=]2001年9月9日]
月工资为14400.0
- 模板方法设计模式是编程中经常用得到的模式。各个框架、类库中都有他的 影子,
- 比如常见的有:
- ? 数据库访问的封装
- ? Junit单元测试
- ? JavaWeb的Servlet中关于doGet/doPost方法调用
- ? Hibernate中模板程序
- ? Spring中JDBCTemlate、HibernateTemplate等
package com.shc.java1;
/*
* 抽象里的应用
* code()那部分
*/
public class TemplateTest {
public static void main(String[] args) {
SubTemplate s = new SubTemplate();
s.spendTime();
}
}
abstract class Template{
//计算某个方法执行所花时间
public void spendTime() {
long start = System.currentTimeMillis();
code(); //不确定的部分,易变的部分
long end = System.currentTimeMillis();
System.out.println(end-start);
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code() {
for(int i=0;i<1000000;i++) {if(i>100)i=i; }
}
}
--------------------------
3 ```
```java
package com.shc.java1;
//抽象类的应用:模板方法的设计模式
public class TemplateMethodTest {
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();
btm.process();
BankTemplateMethod btm2 = new ManageMoney();
btm2.process();
}
}
abstract class BankTemplateMethod {
// 具体方法
public void takeNumber() {
System.out.println("取号排队");
}
public abstract void transact(); // 办理具体的业务 //钩子方法
public void evaluate() {
System.out.println("反馈评分");
}
// 模板方法,把基本操作组合到一起,子类一般不能重写
public final void process() {
this.takeNumber();
this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码
this.evaluate();
}
}
class DrawMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要取款!!!");
}
}
class ManageMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要理财!我这里有2000万美元!!");
}
}
package com.shc.java2;
/*
* 接口的使用
* 1. 接口使用interface来定义
* 2. Java中,接口和类是两个并列的结构
* 3. 如何定义接口,定义接口中的成员
* 3.1 JDk7:以前,只能定义全局常量和抽象方法
* 全局常量:public static final static:只有一份 final:不变的 但是书写时可以省略不写
* 抽象方法:public abstract
* 3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)
*
* 4. 接口中不能定义构造器!
* 意味着接口不可以被实例化。(所以子类实例化时不会调用到接口)
* 5. Java开发中,接口通过让类去实现(implements)的方式来使用
* 如果此实现类覆盖了接口中的所有抽象方法,则此类可以实例化。
* 如果此实现类没有覆盖了接口中的所有抽象方法,则此类仍要声明为abstract。
* 6. 实现 --- 小三角是空心
* 7. Java类可以实现多个接口 -->弥补了Java单继承性的局限性
* 格式:class AA extends BB implements CC,DD,EE
* 8. 接口和接口之间也叫继承关系,并且可以多继承
体会
* 9. 接口的使用可以体现多态性
* 10. 接口,实际上可以看作一种规范
* 11. 开发中,体会面向接口编程!
* proxy
n. 代理权; 代表权; 代理人; 受托人; 代表; (测算用的)代替物,指标;
[例句]Your proxy will need to sign the form on your behalf.
你的代理人将须代表你在表格上签字。
[其他] 复数:proxies
* 面试题:抽象类和接口有哪些异同?
*
*/
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyable.a);
// Flyable.a=1;The final field Flyable.a cannot be assigned
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900;
public static final int MIN_SPEED = 1;
int a = 5;//省略了public static final 但仍然是一个全局常量
//抽象方法
public abstract void fly();
//省略了public abstract
void stop();
}
interface Attach{
public abstract void attach();
}
//如果没有实现接口中的全部抽象方法,此类就要声明为abstract
abstract class plane implements Flyable{
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("plane fly");
}
// @Override
// public void stop() {
// // TODO Auto-generated method stub
// System.out.println("plane stop");
// }
}
class Bullet implements Flyable,Attach{
@Override
public void attach() {
// TODO Auto-generated method stub
}
@Override
public void fly() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
}
/**************************************************/
interface AA{
}
interface CC{
}
interface DD extends AA,CC{
}
接口应用举例
Java应用程序 -- 调JDBC --- 通过JDBC来调数据库。
JDBC可以理解为Java语言去操作数据库的技术。为什么没把JDBC和Java语言基础合在一起? 因为JDBC里定义了大量的接口。JDBC定了很多如何操作数据库的规范。
那么为什么要定义这些规范?因为如果不定义规范的话,不同数据库的操作函数大不相同,量也多。所以Sun公司统一了一套标准规范(抽象的)(规范)(具体如何写由程序员决定)。
编写代码时写的参数就是接口。所以Java程序员目前不是面向数据库编程,而是面向接口编程。在代码中不会看见某一个具体数据库的API。
面向接口编程:我们在应用程序中,调用的结构都是JDBC中定义的接口,不会出现某一个数据库厂商的API
USB接口练习
package com.shc.java2;
/*
* 接口的使用
* 1. 接口的使用上体现多态性 。(函数的父类形参接收子类对象)
* 2. 开发中,面向接口编程
*/
public class USBTest {
public static void main(String[] args) {
Computer computer = new Computer();
//1. 创建了接口的非匿名实现了的非匿名对象
Flash flash = new Flash();
computer.transferDate(flash);//多态
System.out.println("*****");
//2. 创建了接口的非匿名实现类的匿名类对象
computer.transferDate(new Flash());
System.out.println("*****");
//3. 创建了接口的匿名实现类的非匿名类对象
USB usb = new USB() {
@Override
public void start() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
};
computer.transferDate(usb);
System.out.println("********");
//4. 创建了接口的匿名实现类的匿名类对象
computer.transferDate(new USB(){
@Override
public void start() {
System.out.println("匿名start");
}
@Override
public void stop() {
System.out.println("匿名stop");
}
});
}
}
interface USB{
public abstract void start();
public abstract void stop();
}
class Computer{
public void transferDate(USB usb){
usb.start();
System.out.println("具体传输数据的细节");
usb.stop();
}
}
class Flash implements USB{
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("Flash start");
}
@Override
public void stop() {
// TODO Auto-generated method stub
System.out.println("Flash stop");
}
}
class Printer implements USB{
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("Printer start");
}
@Override
public void stop() {
// TODO Auto-generated method stub
System.out.println("Printer stop");
}
}
interface A {
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
// System.out.println(x); 报错 ambigious x 不明确的x
//1. 父类合接口位于同一级别
//2. 无super.super
//3. 接口不是父类的父类
syso(super.x); //1 输出的是B的1
syso(A.x); //0 利用了interface中的属性是全局常量
}
public static void main(String[] args) {
new C().pX();
}
}
int x
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable, Bounceable {
Ball ball = new Ball("PingPang");
}
class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name = name;
}
//算重写了Playable和Bounceable中的play方法都重写了
public void play() {
ball = new Ball("Football");
System.out.println(ball.getName());//!!这里错了!!! Rollable接口中的ball是public static final Ball ball 不能改变指向!
}
}
定义一个接口用来实现两个对象的比较。
interface CompareObject{
? public int compareTo(Object o); //若返回值是 0 , 代表相等; 若为正数,代表当 前对象大;负数代表当前对象小
}
?定义一个
Circle
类,声明redius属性,提供getter和setter方法?定义一个
ComparableCircle
类,继承Circle类并且实现CompareObject接口。在 ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半 径大小。?定义一个测试类
InterfaceTest
,创建两个ComparableCircle对象,调用compareTo
方法比较两个类的半径大小。
package com.shc.exer4;
/*
* 定义一个接口用来实现两个对象的比较。
?interface CompareObject{
public int compareTo(Object o);
//若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
}
*/
public interface ComparObject {
public int compareTo(Object o);
//若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
}
package com.shc.exer4;
public class Circle {
// private double r;
//新写法:
private Double r;
public Circle() {}
public Circle(Double r) {
this.r=r;
}
public Double getR() {
return r;
}
public void setR(Double r) {
this.r = r;
}
}
package com.shc.exer4;
public class ComparableCircle extends Circle implements ComparObject{
// public ComparableCircle() {}
// public ComparableCircle(double r) {
// super(r);
// }
//
// @Override
// public int compareTo(Object o){
// if(this==o) return 0;
// if(o instanceof ComparableCircle) {
// //错误的 因为会有精度损失
//// return (int)(this.getR()-((ComparableCircle)o).getR());
// ComparableCircle t = (ComparableCircle) o; //向下转型 记得给一个强转运算符() 。向上转型不需要(),父类管子类,直接转就可以
// if(super.getR()==t.getR()) return 0;
// return super.getR()>t.getR() ? 1 : -1;
// //this.getR() 和super.getR() 效果一样 因为子类没有重写父类的getR()
// }
// return 0; //只能这样了
// }
//另一种写法 调用Double包装类中的方法
public ComparableCircle() {
// TODO Auto-generated constructor stub
}
public ComparableCircle(Double r) {
super(r);
}
@Override
public int compareTo(Object o){
if(this==o) {return 0;}
if(o instanceof ComparableCircle) {
ComparableCircle t = (ComparableCircle)o;
//使用包装类中的方法
return this.getR().compareTo(t.getR());
}
return -8;
}
}
package com.shc.exer4;
public class InterfaceTest {
public static void main(String[] args) {
ComparableCircle c1 = new ComparableCircle(1.1); //自动装箱 double-->Double
ComparableCircle c2 = new ComparableCircle(2.9);
System.out.println(c1.compareTo(c2));
}
}
-1
package com.shc.jdk8;
public class SubClassTest{
public static void main(String[] args) {
SubClass s = new SubClass();
//1. 接口中定义的静态方法只能通过接口来调用 有点像工具类了哈 都是静态方法
//实现类看不到接口中的静态方法
// s.method1();
CompareA.mehtod1();
//2. 通过实现类的对象可以实现接口中的默认方法
//如果实现类中重写了接口中的默认方法,调用时,仍然调用重写以后的方法
s.method();
//3. 如果子类(或者实现类)继承的父类和实现的接口中声明了同名同参数身为方法,那么子类在没有重写此方法的情况下,调用的是父类中的方法
//称为类优先原则(针对于方法来说)(上道面试题关于接口和父类中的属性重名的时候如果不指明会编译报错)
//4.如果实现类实现了多个接口,而在这多个接口中定义了多个同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。--->接口冲突
//这就需要我们必须重写此方法
//6.在接口的实现类中可以不用重写接口的方法,一定程度上接口越来越像类
//以后看到API中的接口有默认的default方法,在实现子类中可以直接调用
//接口中的方法除了abstract的主要都是default方法 静态static方法看到的少
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
//接口中的抽象方法需要重写 static和default方法不需要重写
// @Override
// public void method3(){}
// @Override
// public void method4(){}
// public void method() {} //可以重写接口中的default方法
public void method5() {}
//5. 如何在实现类的方法中调用父类和接口中被重写的方法
public void myMthod() {
method5(); //调用自己重写的方法
super.method5(); //调用父类中二点方法
CompareA.mehtod1(); //接口名调用静态方法
CompareA.super.method();//接口名+super+default方法()
}
}
package com.shc.jdk8;
/*
* jdk8 除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
* abstract修饰无方法体的抽象方法
* static default修饰有方法体的方法
*/
public interface CompareA {
//可以定义静态方法 即只能由接口调用 原先绝对不可以定义方法,现在向类靠近了
//实现类看不到接口中的静态方法
public static void mehtod1(){System.out.println("hh");}
//声明默认方法
public default void method2(){}
//public可以省略
default void method() {System.out.println("CompareA");}
//
// void method3();
// //<->
// public abstract void method4();
}
package com.shc.jdk8;
public interface CompareB {
public default void method() {System.out.println("CompareB");}
}
package com.shc.jdk8;
public class SuperClass {
public void method() {
System.out.println("SuperClass");
}
public void method5() {
}
}
package com.shc.java8;
public class Man extends Father implements Filial,Spoony{
//如果没有继承父类的话,则必须重写help方法
//虽然接口中没有抽象方法,但是Man还是必须要重写,因为两个接口的方法发生冲突
// @Override
// public void help() {
// // TODO Auto-generated method stub
//// Filial.super.help(); //调用Filial接口的
//// Spoony.super.help(); //调用Spoony接口的
// System.out.println("救谁呢");//重写方法做出决定
// }
//如果继承了父类的话,则不用再重写,不会error,按照父类定义的即可
}
class Father{
public void help() {
System.out.println("救你妈");
}
}
interface Filial{ //孝顺的
default void help() {
System.out.println("老妈,我来救你了");
}
}
interface Spoony{//痴情的
default void help() {
System.out.println("媳妇,我来救你了");
}
}
package com.shc.java2;
/*
* 接口的应用:代理模式
*/
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse(); //调用代理类的方法,代理类在该方法中执行了被代理类要做的事情+代理类要多做的事情
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
// TODO Auto-generated method stub
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work; //接口引用变量 可以去管理覆盖了接口的对象
public ProxyServer(NetWork work) {
this.work = work;
}
@Override
public void browse() {
// TODO Auto-generated method stub
check();
System.out.println("*******");
work.browse();
}
public void check() {
System.out.println("联网之前的检查操作");
}
}```
- **demo2**
```java
package com.shc.java2;
public class StaticProxyTest {
public static void main(String[] args) {
Star s = new Proxy(new RealStar());
s.confer(); //经纪人面谈
s.signContract(); //经纪人签合同
s.bookTicket(); //经纪人订票
s.sing(); //明星:歌唱~~~
s.collectMoney(); //经纪人收钱
}
}
interface Star {
void confer();// 面谈
void signContract();// 签合同
void bookTicket();// 订票
void sing();// 唱歌
void collectMoney();// 收钱
}
class RealStar implements Star {
//为了RealStar可以new对象 即便RealStar不会做这些方法 也要把这些接口中的方法全部覆盖 方法体中没有语句也可以
public void confer() {
}
public void signContract() {
}
public void bookTicket() {
}
public void sing() {
System.out.println("明星:歌唱~~~");
}
public void collectMoney() {
}
}
class Proxy implements Star {
private Star real;//被代理的对象
public Proxy(Star real) {
this.real = real;
}
//代理 去做real不能做的事情
public void confer() {
System.out.println("经纪人面谈");
}
public void signContract() {
System.out.println("经纪人签合同");
}
public void bookTicket() {
System.out.println("经纪人订票");
}
//代理 做只有real能做的事情
public void sing() {
real.sing();
}
public void collectMoney() {
System.out.println("经纪人收钱");
}
}
应用举例
应用场景:
安全代理:屏蔽对真实角色的直接访问。
远程代理:通过代理类处理远程方法调用(RMI)
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象 比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有 100MB,在打开文件时,不可能将所有的图片都显示出来,这样就可以使用代理 模式,当需要查看图片时,用proxy来进行大图片的打开。 ?
分类
- 静态代理(静态定义代理类)
- 动态代理(动态生成代理类)
- JDK自带的动态代理,需要反射等知识
接口的应用:工厂模式
工厂模式:实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离 起来,达到提高灵活性的目的。
其实设计模式和面向对象设计原则都是为了使得开发项目更加容易扩展和维 护,解决方式就是一个“分工”。
社会的发展也是这样,分工越来越细。
原始社会的人:人什么都要会,自己种,自己打猎,自己织衣服,
自己治病 现在的人:可以只会一样,其他都不会,只会 Java 也能活,不会做饭,不会开 车,不会....
/*
* 类的内部成员之五
* 1. Java中允许将一个类声明在另一个类B中,则类A就是内部类,类B称为外部类
*
* 2. 内部类的分类:成员内部类(静态,非静态) vs 局部内部类(方法内,代码块内,构造期内)
*
* 3. 成员内部类的理解:
* 一方面,作为外部类的成员
* 》调用外部类结构
* 》可以被static修饰
* 》可以被4中不同的权限修饰符修饰
* 另一方面,作为一个类
* 》类内,可以定义属性,方法,构造器等
* 》可以被final修饰,表示此类不能被继承,言外之意,不使用final,就可以继承
* 》可以被abstract修饰
* 4. 关注以下3个问题即可
* 4.1 如何实例化成员内部类对象
//创建静态的Bird实例(静态的成员内部类)
Person.Bird pBird = new Person.Bird();
//创建非静态的Dog实例(非静态的成员内部类)
Person p = new Person();
Person.Dog dog = p.new Dog();
*
4.2 如何在成员内部类中区分调用外部类的结构
class Person{
String name = "ywt";
class Dog{ //静态成员内部类
String name="henry";
public void display(String name) {
System.out.println(name);//形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
}
* 4.3 开发中局部内部类的使用,见《InnerClassTest1.java》
* /
//4.3 开发中局部内部类的使用,见《InnerClassTest1.java》
//开发中常见:
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable() {
//为什么这个类不放在外面? 因为这个类只有这里面用
//创建一个实现了Compparable接口的类
//方式一:
// class MyComparablex implements Comparable{
// @Override
// public int compareTo(Object o) {
// // TODO Auto-generated method stub
// return 0;
// }
// }
// return new MyComparablex();
//方式二: 创建并返回了匿名内部类的匿名对象
return new Comparable() {
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
};
}
package com.shc.java3;
/*
* 移动端常见问题
*/
public class InnerTest2 {
/*
* 在局部内部类的方法中(show()),如果调用局部内部类所声明的方法(比如method)中的局部变量的话(比如num)
* 要求此局部变量是一个final
*
* jdk 7及以前的版本,要求此局部变量显示的声明为final的
* jdk 8及之后的版本,可以省略final的声明
*/
public void method() {
//局部变量
int num=10; //final int
class AA{
// num=9;
public void show() {
// num=9; error
//Local variable num defined in an enclosing scope must be final or effectively final
// 在封闭作用域中定义的局部变量num必须是final或有效final
//在内部类中使用外部类的属性成员只能使用不能修改,因为只是从外部类传入了一个副本
//原因:虽然在语法上小的作用域覆盖大的作用域,但是在编译产生.class文件时,外部类和内部类是分别产生了两个.class文件
//(方法存在于外部类)
// //如果在内部类中修改了这个元素,那么在那个.class文件中也需要修改,不好修改。
System.out.println(num);
}
}
}
}
abstract AA{
public abstract void f();
}
public class test{
main{
AA f = new AA(){
@Override
public void abstract(){}
}
}
}
如何创建静态成员内部类和非静态成员内部类的对象?
Person
static Dog
Bird
//创建静态不用new p
Person.Dog = new Persin.Dog();
//创建非静态要new p。因为没有p对象就无法new Bird()
Person p = new Person();
Person.Bird bird = new p.new Person.Bird();
原文:https://www.cnblogs.com/4-Prestar/p/14762681.html