1. Java中的反射

1.1 说说你对Java中反射的理解

Java中的反射首先是能够获取到Java中要反射类的字节码,获取字节码有三种方法

  • Class.forName(className)
  • 类名.class
  • this.getClass()

然后将字节码中的方法,变量,构造函数等映射成相应的Method、Filed、Constructor等类,这些类提供了丰富的方法可以被我们所使用。

2. Java中的动态代理

2.1 写一个ArrayList的动态代理类(笔试题)

  1. final List<String> list = new ArrayList<String>();
  2. List<String> proxyInstance = (List<String>) Proxy.newProxyInstance(list.getClass().getClassLoader(),
  3. list.getClass().getInterfaces(), new InvocationHandler() {
  4. @Override
  5. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  6. return method.invoke(list, args);
  7. }
  8. }
  9. );
  10. proxyInstance.add("你好");
  11. System.out.println(list);

3. Java中的设计模式

3.1 你所知道的设计模式有哪些

Java中一般认为有23种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多越好。

总体来说设计模式分为三大类:

  • 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
  • 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

3.2 单例设计模式

最好理解的一种设计模式,分为懒汉式和饿汉式。

3.2.1 饿汉式

  1. public class Singleton {
  2. // 直接创建对象
  3. public static Singleton instance = new Singleton();
  4. // 私有化构造函数
  5. private Singleton() {
  6. }
  7. // 返回对象实例
  8. public static Singleton getInstance() {
  9. return instance;
  10. }
  11. }

3.2.2 懒汉式

  1. public class Singleton {
  2. // 声明变量
  3. private static volatile Singleton singleton2 = null;
  4. // 私有构造函数
  5. private Singleton2() {
  6. }
  7. // 提供对外方法
  8. public static Singleton2 getInstance() {
  9. if (singleton2 == null) {
  10. synchronized (Singleton2.class) {
  11. if (singleton == null) {
  12. singleton = new Singleton();
  13. }
  14. }
  15. }
  16. return singleton;
  17. }
  18. }

3.3 工厂设计模式

工厂模式分为工厂方法模式和抽象工厂模式。工厂方法模式分为三种

  • 普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建
  • 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象
  • 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可

普通工厂模式

  1. public interface Sender {
  2. public void Send();
  3. }
  4. public class MailSender implements Sender {
  5. @Override
  6. public void Send() {
  7. System.out.println("this is mail sender!");
  8. }
  9. }
  10. public class SmsSender implements Sender {
  11. @Override
  12. public void Send() {
  13. System.out.println("this is sms sender!");
  14. }
  15. }
  16. public class SendFactory {
  17. public Sender produce(String type) {
  18. if ("mail".equals(type)) {
  19. return new MailSender();
  20. } else if ("sms".equals(type)) {
  21. return new SmsSender();
  22. } else {
  23. System.out.println("请输入正确的类型!");
  24. return null;
  25. }
  26. }
  27. }

多个工厂方法模式

该模式是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

  1. public class SendFactory {
  2. public Sender produceMail(){
  3. return new MailSender();
  4. }
  5. public Sender produceSms(){
  6. return new SmsSender();
  7. }
  8. }
  9. public class FactoryTest {
  10. public static void main(String[] args) {
  11. SendFactory factory = new SendFactory();
  12. Sender sender = factory.produceMail();
  13. sender.send();
  14. }
  15. }

静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

  1. public class SendFactory {
  2. public static Sender produceMail(){
  3. return new MailSender();
  4. }
  5. public static Sender produceSms(){
  6. return new SmsSender();
  7. }
  8. }
  9. public class FactoryTest {
  10. public static void main(String[] args) {
  11. Sender sender = SendFactory.produceMail();
  12. sender.send();
  13. }
  14. }

抽象工厂模式

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

  1. public interface Provider {
  2. public Sender produce();
  3. }
  4. public interface Sender {
  5. public void send();
  6. }
  7. public class MailSender implements Sender {
  8. @Override
  9. public void send() {
  10. System.out.println("this is mail sender!");
  11. }
  12. }
  13. public class SmsSender implements Sender {
  14. @Override
  15. public void send() {
  16. System.out.println("this is sms sender!");
  17. }
  18. }
  19. public class SendSmsFactory implements Provider {
  20. @Override
  21. public Sender produce() {
  22. return new SmsSender();
  23. }
  24. }
  25. public class SendMailFactory implements Provider {
  26. @Override
  27. public Sender produce() {
  28. return new MailSender();
  29. }
  30. }
  31. public class Test {
  32. public static void main(String[] args) {
  33. Provider provider = new SendMailFactory();
  34. Sender sender = provider.produce();
  35. sender.send();
  36. }
  37. }

3.4 建造者模式(Builder)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。

  1. public class Builder {
  2. private List<Sender> list = new ArrayList<Sender>();
  3. public void produceMailSender(int count) {
  4. for (int i = 0; i < count; i++) {
  5. list.add(new MailSender());
  6. }
  7. }
  8. public void produceSmsSender(int count) {
  9. for (int i = 0; i < count; i++) {
  10. list.add(new SmsSender());
  11. }
  12. }
  13. }
  14. public class TestBuilder {
  15. public static void main(String[] args) {
  16. Builder builder = new Builder();
  17. builder.produceMailSender(10);
  18. }
  19. }

3.5 适配器设计模式

适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。

类的适配器模式

  1. public class Source {
  2. public void method1() {
  3. System.out.println("this is original method!");
  4. }
  5. }
  6. public interface Targetable {
  7. /* 与原类中的方法相同 */
  8. public void method1();
  9. /* 新类的方法 */
  10. public void method2();
  11. }
  12. public class Adapter extends Source implements Targetable {
  13. @Override
  14. public void method2() {
  15. System.out.println("this is the targetable method!");
  16. }
  17. }
  18. public class AdapterTest {
  19. public static void main(String[] args) {
  20. Targetable target = new Adapter();
  21. target.method1();
  22. target.method2();
  23. }
  24. }

对象的适配器模式

基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。

  1. public class Wrapper implements Targetable {
  2. private Source source;
  3. public Wrapper(Source source) {
  4. super();
  5. this.source = source;
  6. }
  7. @Override
  8. public void method2() {
  9. System.out.println("this is the targetable method!");
  10. }
  11. @Override
  12. public void method1() {
  13. source.method1();
  14. }
  15. }
  16. public class AdapterTest {
  17. public static void main(String[] args) {
  18. Source source = new Source();
  19. Targetable target = new Wrapper(source);
  20. target.method1();
  21. target.method2();
  22. }
  23. }

接口的适配器模式

接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

3.6 装饰模式(Decorator)

顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。

  1. public interface Sourceable {
  2. public void method();
  3. }
  4. public class Source implements Sourceable {
  5. @Override
  6. public void method() {
  7. System.out.println("the original method!");
  8. }
  9. }
  10. public class Decorator implements Sourceable {
  11. private Sourceable source;
  12. public Decorator(Sourceable source) {
  13. super();
  14. this.source = source;
  15. }
  16. @Override
  17. public void method() {
  18. System.out.println("before decorator!");
  19. source.method();
  20. System.out.println("after decorator!");
  21. }
  22. }
  23. public class DecoratorTest {
  24. public static void main(String[] args) {
  25. Sourceable source = new Source();
  26. Sourceable obj = new Decorator(source);
  27. obj.method();
  28. }
  29. }

3.7 策略模式(strategy)

策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。

  1. public interface ICalculator {
  2. public int calculate(String exp);
  3. }
  4. public class Minus extends AbstractCalculator implements ICalculator {
  5. @Override
  6. public int calculate(String exp) {
  7. int arrayInt[] = split(exp, "-");
  8. return arrayInt[0] - arrayInt[1];
  9. }
  10. }
  11. public class Plus extends AbstractCalculator implements ICalculator {
  12. @Override
  13. public int calculate(String exp) {
  14. int arrayInt[] = split(exp, "\\+");
  15. return arrayInt[0] + arrayInt[1];
  16. }
  17. }
  18. public class AbstractCalculator {
  19. public int[] split(String exp, String opt) {
  20. String array[] = exp.split(opt);
  21. int arrayInt[] = new int[2];
  22. arrayInt[0] = Integer.parseInt(array[0]);
  23. arrayInt[1] = Integer.parseInt(array[1]);
  24. return arrayInt;
  25. }
  26. }
  27. public class StrategyTest {
  28. public static void main(String[] args) {
  29. String exp = "2+8";
  30. ICalculator cal = new Plus();
  31. int result = cal.calculate(exp);
  32. System.out.println(result);
  33. }
  34. }

3.8 观察者模式(Observer)

观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。

  1. public interface Observer {
  2. public void update();
  3. }
  4. public class Observer1 implements Observer {
  5. @Override
  6. public void update() {
  7. System.out.println("observer1 has received!");
  8. }
  9. }
  10. public class Observer2 implements Observer {
  11. @Override
  12. public void update() {
  13. System.out.println("observer2 has received!");
  14. }
  15. }
  16. public interface Subject {
  17. /*增加观察者*/
  18. public void add(Observer observer);
  19. /*删除观察者*/
  20. public void del(Observer observer);
  21. /*通知所有的观察者*/
  22. public void notifyObservers();
  23. /*自身的操作*/
  24. public void operation();
  25. }
  26. public abstract class AbstractSubject implements Subject {
  27. private Vector<Observer> vector = new Vector<Observer>();
  28. @Override
  29. public void add(Observer observer) {
  30. vector.add(observer);
  31. }
  32. @Override
  33. public void del(Observer observer) {
  34. vector.remove(observer);
  35. }
  36. @Override
  37. public void notifyObservers() {
  38. Enumeration<Observer> enumo = vector.elements();
  39. while (enumo.hasMoreElements()) {
  40. enumo.nextElement().update();
  41. }
  42. }
  43. }
  44. public class MySubject extends AbstractSubject {
  45. @Override
  46. public void operation() {
  47. System.out.println("update self!");
  48. notifyObservers();
  49. }
  50. }
  51. public class ObserverTest {
  52. public static void main(String[] args) {
  53. Subject sub = new MySubject();
  54. sub.add(new Observer1());
  55. sub.add(new Observer2());
  56. sub.operation();
  57. }
  58. }