20220727_第七小组_张红睿_学习笔记

Java基础第十五天

image

1. 代码块

1.1 概念

代码块又叫初始化块,属于类的一个成员,将逻辑语句封装在方法中,放在大括号内。

代码块没有方法名、没有参数、没有返回值只有方法体。

代码块是被自动加载的,即隐式调用。

1.2 联系

静态代码块 实例代码块
语法 static{ 方法体 } { 方法体 }
加载 加载类时 实例化对象时
数量 可以有多个,但一般只写一个 可以有多个,但一般只写一个

1.3 继承关系下与构造器的执行顺序

public class A {
    static {
        System.out.println("父类的静态代码块");
    }

    {
        System.out.println("父类的实例代码块");
    }

    public A(){
        System.out.println("父类的构造函数");
    }
}

public class B extends A{
    static {
        System.out.println("子类的静态代码块");
    }

    {
        System.out.println("子类的实例代码块");
    }

    public B(){
        System.out.println("子类的构造函数");
    }

    public static void main(String[] args) {
        B b = new B();
    }
}

2. 静态(static)

  • 静态变量:static int a;
  • 静态方法:static void function(){}
  • 静态代码块:static

理解:

​ 静态修饰的变量、方法、代码块都属于类,在类被加载时进行加载,所以在静态方法中不能直接引用实例属性或方法,但可以通过实例化对象的方式进行调用。类外可通过类名.的方式进行调用,也可以通过实例化对象进行调用。

​ 区别于实例属性及方法,它们均属于对象,类中可通过this关键字进行调用。

注意:静态方法没有重写的概念。

3.面向对象的设计原则

面向对象设计原则是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心。

原则1:DRY(Don't repeat yourself)

​ 即不要写重复的代码,而是用“abstraction”类来抽象公有的东西。如果你需要多次用到一个硬编码值,那么可以设为公共常量;如果你要在两个以上的地方使用一个代码块,那么可以将它设为一个独立的方法。SOLID设计原则的优点是易于维护,但要注意,不要滥用,duplicate 不是针对代码,而是针对功能。这意味着,即使用公共代码来验证OrderID和SSN,二者也不会是相同的。使用公共代码来实现两个不同的功能,其实就是近似地把这两个功能永远捆绑到了一起,如果OrderID改变了其格式,SSN验证代码也会中断。因此要慎用这种组合,不要随意捆绑类似但不相关的功能。

原则2:封装变化

​ 在软件领域中唯一不变的就是“Change”,因此封装你认为或猜测未来将发生变化的代码。OOPS设计模式的优点在于易于测试和维护封装的代码。如果你使用Java编码,可以默认私有化变量和方法,并逐步增加访问权限,比如从private到protected和not public。有几种Java设计模式也使用封装,比如Factory设计模式是封装“对象创建”,其灵活性使得之后引进新代码不会对现有的代码造成影响。

原则3:开闭原则

​ 即对扩展开放,对修改关闭。这是另一种非常棒的设计原则,可以防止其他人更改已经测试好的代码。理论上,可以在不修改原有的模块的基础上,扩展功能。这也是开闭原则的宗旨。

原则4:单一职责原则

​ 类被修改的几率很大,因此应该专注于单一的功能。如果你把多个功能放在同一个类中,功能之间就形成了关联,改变其中一个功能,有可能中止另一个功能,这时就需要新一轮的测试来避免可能出现的问题。

原则5:依赖注入或倒置原则

​ 这个设计原则的亮点在于任何被DI框架注入的类很容易用mock对象进行测试和维护,因为对象创建代码集中在框架中,客户端代码也不混乱。有很多方式可以实现依赖倒置,比如像AspectJ等的AOP(Aspect Oriented programming)框架使用的字节码技术,或Spring框架使用的代理等。

原则6:优先利用组合而非继承

​ 如果可能的话,优先利用组合而不是继承。一些人可能会质疑,但我发现,组合比继承灵活得多。组合允许在运行期间通过设置类的属性来改变类的行为,也可以通过使用接口来组合一个类,它提供了更高的灵活性,并可以随时实现。

原则7:里氏代换原则(LSP)

​ 根据该原则,子类必须能够替换掉它们的基类,也就是说使用基类的方法或函数能够顺利地引用子类对象。LSP原则与单一职责原则和接口分离原则密切相关,如果一个类比子类具备更多功能,很有可能某些功能会失效,这就违反了LSP原则。为了遵循该设计原则,派生类或子类必须增强功能。

原则8:接口分离原则

​ 采用多个与特定客户类有关的接口比采用一个通用的涵盖多个业务方法的接口要好。设计接口很棘手,因为一旦释放接口,你就无法在不中断执行的情况下改变它。在Java中,该原则的另一个优势在于,在任何类使用接口之前,接口不利于实现所有的方法,所以单一的功能意味着更少的实现方法。

原则9:针对接口编程,而不是针对实现编程

​ 该原则可以使代码更加灵活,以便可以在任何接口实现中使用。因此,在Java中最好使用变量接口类型、方法返回类型、方法参数类型等。

原则10:委托原则

​ 该原则最典型的例子是Java中的equals() 和 hashCode() 方法。为了平等地比较两个对象,我们用类本身而不是客户端类来做比较。这个设计原则的好处是没有重复的代码,而且很容易对其进行修改。

4. 单例模式

4.1 饿汉式

public class SingletonPatternHungry{
    private static final INSTANCE = new SingletonPatternHungry();
    private SingletonPatternHungry(){}
    public static SingletonPatternHungry getInstance(){
        return SingletonPatternHungry.INSTANCE;
    }
}

优点:写法简单、避免线程同步。

缺点:如果未使用会造成内存浪费。

4.2 懒汉式

public class SingletonPatternLazy{
    private static instance;
    private SingletonPatternLazy(){}
    public static SingletonPatternLazy getInstance(){
        if(SingletonPatternLazy == null)
            instance = new SingletonPatternLazy();
        return SingletonPatternLazy.instance;
    }
}

优点:可以避免内存浪费。

缺点:可能会产生多个实例、且不适用于多线程。

4.3 静态内部类【推荐使用】

public class Singleton{
    private Singleton(){}
    private static class SingletonInstance{
        private static final Singleton INSTANCE = new Singeton();
    }
    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;		
    }
}

优点:避免了线程不安全,延迟加载,效率高。

4.4 双链表

package com.jsoft.linklist;

import java.util.Iterator;

public class DoubleLinkList<T> implements Iterable<T> {
    private Node head;      // 头结点
    private Node tail;      // 尾指针
    private Integer length; // 链表有效长度

    private class Node{
        private T data;     // 数据域
        private Node prior; // 指针域 前
        private Node next;  // 指针域 后

        public Node(){}
        public Node(T data){
            this.data = data;
        }
    }

    public DoubleLinkList(){
        this.head = new Node();
        this.length = 0;
    }

    public Integer getLength(){
        return this.length;
    }

    public Boolean isEmpty(){
        return this.length == 0;
    }

    /**
     * 尾插
     * @param data 插入的数据
     */
    public void addNode(T data){
        Node tmp = this.head;
        while(tmp.next != null)
            tmp = tmp.next;
        Node newNode = new Node(data);
        tmp.next = newNode;
        newNode.prior = tmp;
        this.length++;
    }

    /**
     * 根据下标删除节点
     * @param index
     */
    public void deleteNode(Integer index){
        if(index < 0 || index >= this.length)
            return;
        Node tmp = this.head;
        while(tmp.next != null && index-- != 0)
            tmp = tmp.next;
        Node delNode = tmp.next;
        delNode.next.prior = tmp;
        tmp.next = delNode.next;
        this.length--;
    }

    /**
     * 通过下标查询节点并返回数据
     * @param index
     * @return
     */
    public T selectNode(Integer index){
        if(index < 0 || index >= this.length)
            return null;
        Node tmp = this.head;
        while(tmp.next != null && index-- != 0)
            tmp = tmp.next;
        return tmp.next.data;
    }

    /**
     * 通过下标进行修改节点
     * @param index
     * @param newData
     */
    public void updateNode(Integer index, T newData){
//        if(index < 0 || index >= this.length)
//            return;
        Node tmp = this.head;
        while (tmp.next != null && index-- != 0)
            tmp = tmp.next;
        if(index == 0) {
            tmp.next.data = newData;
        }
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        for (T data : this) {
            stringBuilder.append(data).append(" ");
        }
        return stringBuilder.append("\n").toString();
    }

    @Override
    public boolean equals(Object obj) {
        DoubleLinkList compareList = (DoubleLinkList) obj;
        if(!this.length.equals(compareList.length))
            return false;
        Node tmp = this.head;
        Node tmp2 = compareList.head;
        while (tmp.next != null && tmp2.next != null){
            if(!tmp.next.data.equals(tmp2.next.data))
                return false;
            tmp = tmp.next;
            tmp2 = tmp2.next;
        }
        return true;
    }

    @Override
    public Iterator<T> iterator() {
        return new DIterator();
    }

    private class DIterator implements Iterator{
        private Node node;
        DIterator(){
            node = DoubleLinkList.this.head;
        }

        @Override
        public boolean hasNext() {
            return node.next != null;
        }

        @Override
        public Object next() {
            node = node.next;
            return node.data;
        }
    }

    public static void main(String[] args) {
        DoubleLinkList<Integer> doubleLinkList = new DoubleLinkList<>();
        System.out.println(doubleLinkList);
        doubleLinkList.addNode(1);
        doubleLinkList.addNode(2);
        doubleLinkList.addNode(3);
        doubleLinkList.addNode(4);
        System.out.println(doubleLinkList);

        doubleLinkList.deleteNode(4);
        doubleLinkList.deleteNode(0);
        doubleLinkList.deleteNode(4);
        System.out.println(doubleLinkList);

        System.out.println(doubleLinkList.selectNode(3));
        System.out.println(doubleLinkList.selectNode(2));
        System.out.println(doubleLinkList);

        doubleLinkList.updateNode(0, 10);
        doubleLinkList.updateNode(100, 10);
        System.out.println(doubleLinkList);
    }
}

4.5 箭头函数(JDK8新特性)

函数式接口:内部仅含有一个抽象方法的接口。可用注解@FunctionalInterface

利用的是lambda表达式

// FunInterface.java
@FunctionalInterface
public interface FunInterface {
    String show(Object ...arr);
}   

// ArrowFunction.java
public class ArrowFunction {
    public static void test(FunInterface funInterface){
        System.out.println(funInterface.show(1, 2, 3));
    }

    public static void main(String[] args) {
        test(new FunInterface() {
            @Override
            public String show(Object... arr) {
                return Arrays.toString(arr);
            }
        });
    }
}

1. 有参有返回值

// FunInterface.java
@FunctionalInterface
public interface FunInterface {
    String show(Object ...arr);
}   

// ArrowFunction.java
public class ArrowFunction {
    public static void test(FunInterface funInterface){
        System.out.println("有参有返回值");
        System.out.println(funInterface.show(1, 2, 3));
    }

    public static void main(String[] args) {
        test(arr -> {
            int length = arr.length;
            return Arrays.toString(arr) + length;
        });
        
        // 只有一行函数体可以省略大括号
        test(arr -> Arrays.toString(arr)); // ==> test(Arrays::toString); 
    }
}

2. 有参无返回值

// FunInterface.java
@FunctionalInterface
public interface FunInterface {
    void show(Object ...arr);
}   

// ArrowFunction.java
public class ArrowFunction {1
    public static void test(FunInterface funInterface){
        System.out.println("有参无返回值");
        funInterface.show(1, 2, 3);
    }

    public static void main(String[] args) {
        test(arr -> System.out.println(Arrays.toString(arr)));
    }
}

3. 无参有返回值

// FunInterface.java
@FunctionalInterface
public interface FunInterface {
    String show();
}   

// ArrowFunction.java
public class ArrowFunction {
    public static void test(FunInterface funInterface){
        System.out.println("无参有返回值");
        System.out.println(funInterface.show());
    }

    public static void main(String[] args) {
        test(() -> Arrays.toString(new int[]{1, 2, 3}));
    }
}

4. 无参无返回值

// FunInterface.java
@FunctionalInterface
public interface FunInterface {
    void show(Object ...arr);
}   

// ArrowFunction.java
public class ArrowFunction {
    public static void test(FunInterface funInterface){
        System.out.println("无参无返回值");
        funInterface.show();
    }

    public static void main(String[] args) {
        test(() -> System.out.println(Arrays.toString(new int[]{1, 2, 3})));
    }
}

posted @ 2022-07-27 21:58  jzhr  阅读(30)  评论(1编辑  收藏  举报