静态代理
在多线程的代码示例的博客中,我们使用到了new Thread(race,"兔子").start();
这句代码,这其实就是静态代理,
在那篇博客中,我们自定义了Race
类,之后创建了该类对象,这个对象就相当于龟兔赛跑中的跑道,之后创建两个线程同时启动,模拟龟兔赛跑,而之所以执行new Thread(race,"兔子").start();
是因为Race
类所创建的对象不能自己开启多线程,所以需要交给Thread
类的构造方法后调用start()
方法来开启多线程,相当于交给了代理
举例:如果你结婚,你必须参加,而且必须请婚庆公司,婚庆公司就相当于代理,而你和婚庆公司的目的都一样,都是完成结婚
-
结婚相当于一个接口,需要你和婚庆公司这两个类来实现
//共同的接口:结婚 interface Marry{ void happyMarry(); //需要被子类重写的方法 }
-
之后自定义
你
类,来作为参加结婚的对象//真实对象:你 class You implements Marry{ @Override public void happyMarry() { System.out.println("我要结婚了,好hi呦"); } }
-
自定义
婚庆公司
类,这个类相当于代理,代理需要代理一个真实对象//代理对象:婚庆公司 class WeddingCompany implements Marry{ //结婚需要有你这个人 , 代理对象需要代理一个真实对象 private Marry you; public WeddingCompany(Marry you){ //构造方法 this.you = you; } @Override public void happyMarry() { //重写接口中的方法 before(); this.you.happyMarry();//你要结婚 //调用成员变量的成员方法 after(); } private void before() { //自定义两个简单方法 System.out.println("结婚之前,布置洞房"); } private void after() { System.out.println("结婚之后,催你收钱"); } }
-
在定义完
你
类和婚庆公司
类后,就可以创建对象调用方法public class StaticProxy { public static void main(String[] args) { //代理对象 代理 真实对象 You you = new You(); you.happyMarry(); new WeddingCompany(you).happyMarry(); } }
在主方法中先创建一个You
类来作为参加婚礼的真实对象,之后交给代理
来让代理进行后续的操作,这就是我们所说的静态代理
上面的代码new WeddingCompany(you).happyMarry();
和new Thread(race,"兔子").start();
格式一样,也就是说我们多线程(线程概念、代码示例)中提到的第二种线程对象的创建方式实际上是使用了静态代理
我们自定义的类虽然实现了runnable
接口,但是这个类的对象还是不能自己开启线程,所以就需要让Thread
类来作为代理,并且调用代理的方法来开启线程,这也就是上面讲到的静态代理
将上面的代码块合并:
package org.westos.java1;
//静态代理
public class StaticProxy {
public static void main(String[] args) {
//代理对象 代理 真实对象
You you = new You();
you.happyMarry();
new WeddingCompany(you).happyMarry();
}
}
//真实对象:你
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("我要结婚了,好hi呦");
}
}
//代理对象:婚庆公司
class WeddingCompany implements Marry{
//婚庆需要有你这个人 , 代理对象需要代理一个真实对象
private Marry you;
public WeddingCompany(Marry you){
this.you = you;
}
@Override
public void happyMarry() {
before();
this.you.happyMarry();//你要结婚
after();
}
private void before() {
System.out.println("结婚之前,布置洞房");
}
private void after() {
System.out.println("结婚之后,催你收钱");
}
}
//共同的接口:结婚
interface Marry{
void happyMarry();
}
运行结果为:
我要结婚了,好hi呦
结婚之前,布置洞房
我要结婚了,好hi呦
结婚之后,催你收钱
Lambda表达式
在编写Java程序时,可能会用到某些接口,所以就需要我们在主程序外单独定义一个类来实现该接口,之后才能在主方法或其他类中使用,这样虽然很好理解,但会使代码太过冗长,所以就引入了 Lambda表达式来简化代码,但是使用Lambda表达式要求接口中只含有一个抽象方法,这种接口也叫做函数式接口
使用函数式接口1:外部类
package org.westos.java1;
public class MyTest {
public static void main(String[] args) {
Ilove love = new love(); //多态
love.lam(1);
}
}
//函数式接口
interface Ilove{
void lam(int a);
}
//外部类
class love implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
这就是我们之前最常用的一种方法来使用接口
使用函数式接口2:静态内部类
package org.westos.java1;
public class MyTest {
//静态内部类
static class love1 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
public static void main(String[] args) {
Ilove love = new love(); //多态
love.lam(1);
love = new love1(); //多态
love.lam(2);
}
}
//函数式接口
interface Ilove{
void lam(int a);
}
//外部类
class love implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
将外部类的代码块放到类中方法外并且加上static
关键字可以实现静态内部类
使用函数式接口3:局部内部类
package org.westos.java1;
public class MyTest {
//静态内部类
static class love1 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
public static void main(String[] args) {
//局部内部类
class love2 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
Ilove love = new love(); //多态
love.lam(1);
love = new love1(); //多态
love.lam(2);
love = new love2(); //多态
love.lam(3);
}
}
//函数式接口
interface Ilove{
void lam(int a);
}
//外部类
class love implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
将外部类代码块直接放入主方法中可以实现局部内部类
使用函数式接口4:匿名内部类
匿名内部类,顾名思义这个类没有名字,因为不需要自定义类,直接使用接口并重写接口中的抽象方法便可以实现对函数式接口的使用,可以看做直接创建了一个接口的对象,虽然这样说法有问题,但最有助于理解
package org.westos.java1;
public class MyTest {
//静态内部类
static class love1 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
public static void main(String[] args) {
//局部内部类
class love2 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
Ilove love = new love(); //多态
love.lam(1);
love = new love1(); //多态
love.lam(2);
love = new love(); //多态
love.lam(3);
//匿名内部类
love = new Ilove() { //这是使用匿名内部类的标准格式,在以后编程中,如果有方法的参数是个接口,我们即可以传入一个实现该接口的子类的对象,也可以直接使用匿名内部类
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
};
love.lam(4);
}
}
//函数式接口
interface Ilove{
void lam(int a);
}
//外部类
class love implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
如果某个接口我们只使用了一次,使用匿名内部类非常方便,但是可以对匿名内部类的代码块进行简化,这也就是我们提到的Lambda表达式
使用函数式接口5:Lambda表达式
package org.westos.java1;
public class MyTest {
//静态内部类
static class love1 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
public static void main(String[] args) {
//局部内部类
class love2 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
Ilove love = new love(); //多态
love.lam(1);
love = new love1();
love.lam(2);
love = new love();
love.lam(3);
//匿名内部类
love = new Ilove() {
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
};
love.lam(4);
//lambda表达式
love = (int a) -> {
System.out.println("我喜欢lambda" + a);
};
love.lam(5);
}
}
//函数式接口
interface Ilove{
void lam(int a);
}
//外部类
class love implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
Lambda表达式代码块如下:
//lambda表达式
love = (int a) -> {
System.out.println("我喜欢lambda" + a);
};
love.lam(5);
匿名内部类代码块:
//匿名内部类
love = new Ilove() {
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
};
love.lam(4);
将二者进行对比可以看到Lambda表达式实际上是将匿名内部类中的
new Ilove() {
@Override
public void lam
代码进行省略,并且在参数和花括号中间加上箭头,这就是Lambda表达式的标准格式,当然这并不是最简
- 在如果重写的函数式接口的抽象方法中只有一句代码就可以直接省略花括号
- 可以省略变量
a
之前的数据类型关键字,如果有多个参数,可以选择都保留或都省略数据类型关键字,但是不能一个保留数据类型关键字,一个省略数据类型关键字 - 如果只有一个参数,可以省略将参数括起来的圆括号
所以上述Lambda表达式的最简格式为:
//lambda表达式
love = a -> System.out.println("我喜欢lambda" + a);
love.lam(5);
但这也只是特殊情况,因为该抽象方法只需要一个参数,而且方法内部只有一句代码
注意:只有函数式接口才能使用Lambda表达式
代码示例:
package lainxi;
//lambda表达式在多线程中的使用
public class Test04 {
public static void main(String[] args) {
//匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("你好1");
}
}).start();
//Lambda表达式
//线程体只有一行可以省略到极致
new Thread(()-> System.out.println("你好2")).start();
//如果线程体有多行 , 用一个代码块包裹起来就好.
new Thread(()-> {
for (int i = 0; i < 5; i++) {
System.out.println("你好3");
}
}).start();
}
}