欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

类与对象03

程序员文章站 2022-04-05 19:50:04
...

1、接口

接口技术,这种技术主要用来描述类具有什么功能,而并不给出每个功能的具体实现

一个类可以实现(implement)一个或多个接口,并在需要接口的地方,随时可以使用实现了相应接口的对象

类与对象03

1.1、什么是接口

  1. 接口不是类,而是对类的一组需求描述(规则,规范),这些类要遵守接口描述的统一格式进行定义
  2. 如果类遵从某个特定的接口,那么就履行这项服务

例如:Arrays类中的Sort方法可以对对象数组进行排序,但要求满足下列前提:对象所属的类必须实现了Comparable接口:

public interface Comparable<T> {
   public int compareTo(T o); 
}

 /**
     * Sorts the specified array of objects according to the order induced by
     * the specified comparator.  All elements in the array must be
     * <i>mutually comparable</i> by the specified comparator (that is,
     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
     * for any elements {@code e1} and {@code e2} in the array).
     *
     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
     * not be reordered as a result of the sort.
     *
     * <p>Implementation note: This implementation is a stable, adaptive,
     * iterative mergesort that requires far fewer than n lg(n) comparisons
     * when the input array is partially sorted, while offering the
     * performance of a traditional mergesort when the input array is
     * randomly ordered.  If the input array is nearly sorted, the
     * implementation requires approximately n comparisons.  Temporary
     * storage requirements vary from a small constant for nearly sorted
     * input arrays to n/2 object references for randomly ordered input
     * arrays.
     *
     * <p>The implementation takes equal advantage of ascending and
     * descending order in its input array, and can take advantage of
     * ascending and descending order in different parts of the the same
     * input array.  It is well-suited to merging two or more sorted arrays:
     * simply concatenate the arrays and sort the resulting array.
     *
     * <p>The implementation was adapted from Tim Peters's list sort for Python
     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
     * Sorting and Information Theoretic Complexity", in Proceedings of the
     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
     * January 1993.
     *
     * @param <T> the class of the objects to be sorted
     * @param a the array to be sorted
     * @param c the comparator to determine the order of the array.  A
     *        {@code null} value indicates that the elements'
     *        {@linkplain Comparable natural ordering} should be used.
     * @throws ClassCastException if the array contains elements that are
     *         not <i>mutually comparable</i> using the specified comparator
     * @throws IllegalArgumentException (optional) if the comparator is
     *         found to violate the {@link Comparator} contract
     */
    public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null)
            c = NaturalOrder.INSTANCE;
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, c);
        else
            TimSort.sort(a, 0, a.length, c, null, 0, 0);
    }



1.2、接口特性

  1. 接口中的所有方法自动为public,因此,在接口声明方法时,不必提供关键字public

  2. 接口中可以包含多个方法

  3. 接口中可以定义常量

  4. 接口中不能包含实例域

  5. Java SE8之后可以在接口中提供简单的方法,当然,这些方法不能引用实例域—接口没有实例

  6. 提供实例域和方法实现的任务应该由实现接口的那个类完成,因此可以将接口看成是没有实例域的抽象类。

  7. 为了让类实现一个接口,通常需要下面两个步骤:

    ​ 7.1、将类声明为实现给定的接口

    ​ 7.2、对接口中的所有方法进行定义


    1. 接口不是类,尤其不能使用new运算符实例化一个接口
    2. 能声明接口变量Comparable x;接口变量必须引用实现了接口的类对象
    3. 接口之间可以实现继承扩展,interface A extends B
    4. 类可以实现多个接口,但是却只能继承一个类(无论是否为抽象类)
    5. 不能包含实例域;可以提供简单的方法,包含常量接口中方法自动设置为public;接口中的域自动设置为public static final

1.3、实现Comparable接口举例

要将类声明为实现某个接口,需要使用关键字implements:

public class Employee extends Person implements Comparable{
    
}

实现CompareTo方法的实现

 //根据雇员的薪水进行比较

    /**
     *
     * @param o
     * @return
     * 在接口声明中,没有将CompareTo方法声明为public
     * 这是因为在接口中的所有方法都自动的是public。
     * 不过,在实现接口时,必须把方法声明为public;
     */
    @Override
    public int compareTo(Object o) {
        Employee other = (Employee)o;
        return Double.compare(salary,other.salary);
    }

在接口声明中,没有将CompareTo方法声明为public,这时因为在接口中的所有方法都自动的是public

不过在实现接口时,必须把方法声明为public;否则编译期将认为这个方法的访问属性是包可见性,即类的默认访问属性

1.4、接口与抽象类

问题1:为什么有了抽象类还需要接口?

Java的类继承不支持多重继承;接口可以提供多重继承的大多数好处,同时可以避免多重继承的复杂性和低效性。

1.5、接口中的方法–抽象方法和默认方法和静态方法

1.5.1、静态方法

在JavaSE8中,允许在接口中增加静态方法。

理论上讲,没有任何理由认为这是不合法的。只是这有违于将接口作为抽象规范的初衷

目前为止,通常的做法都是将静态方法放在伴宿类中。

在标准库中,会看到成对出现的接口和实用工具类:入Collection/Collections

package java.util;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * This class consists exclusively of static methods that operate on or return
 * collections.  It contains polymorphic algorithms that operate on
 * collections, "wrappers", which return a new collection backed by a
 * specified collection, and a few other odds and ends.
 *
 * <p>The methods of this class all throw a <tt>NullPointerException</tt>
 * if the collections or class objects provided to them are null.
 *
 * <p>The documentation for the polymorphic algorithms contained in this class
 * generally includes a brief description of the <i>implementation</i>.  Such
 * descriptions should be regarded as <i>implementation notes</i>, rather than
 * parts of the <i>specification</i>.  Implementors should feel free to
 * substitute other algorithms, so long as the specification itself is adhered
 * to.  (For example, the algorithm used by <tt>sort</tt> does not have to be
 * a mergesort, but it does have to be <i>stable</i>.)
 *
 * <p>The "destructive" algorithms contained in this class, that is, the
 * algorithms that modify the collection on which they operate, are specified
 * to throw <tt>UnsupportedOperationException</tt> if the collection does not
 * support the appropriate mutation primitive(s), such as the <tt>set</tt>
 * method.  These algorithms may, but are not required to, throw this
 * exception if an invocation would have no effect on the collection.  For
 * example, invoking the <tt>sort</tt> method on an unmodifiable list that is
 * already sorted may or may not throw <tt>UnsupportedOperationException</tt>.
 *
 * <p>This class is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @see     Collection
 * @see     Set
 * @see     List
 * @see     Map
 * @since   1.2
 */

public class Collections {
    // Suppresses default constructor, ensuring non-instantiability.
    private Collections() {
    }

    // Algorithms

    /*
     * Tuning parameters for algorithms - Many of the List algorithms have
     * two implementations, one of which is appropriate for RandomAccess
     * lists, the other for "sequential."  Often, the random access variant
     * yields better performance on small sequential access lists.  The
     * tuning parameters below determine the cutoff point for what constitutes
     * a "small" sequential access list for each algorithm.  The values below
     * were empirically determined to work well for LinkedList. Hopefully
     * they should be reasonable for other sequential access List
     * implementations.  Those doing performance work on this code would
     * do well to validate the values of these parameters from time to time.
     * (The first word of each tuning parameter name is the algorithm to which
     * it applies.)
     */
    private static final int BINARYSEARCH_THRESHOLD   = 5000;
    private static final int REVERSE_THRESHOLD        =   18;
    private static final int SHUFFLE_THRESHOLD        =    5;
    private static final int FILL_THRESHOLD           =   25;
    private static final int ROTATE_THRESHOLD         =  100;
    private static final int COPY_THRESHOLD           =   10;
    private static final int REPLACEALL_THRESHOLD     =   11;
    private static final int INDEXOFSUBLIST_THRESHOLD =   35;

    /**
     * Sorts the specified list into ascending order, according to the
     * {@linkplain Comparable natural ordering} of its elements.
     * All elements in the list must implement the {@link Comparable}
     * interface.  Furthermore, all elements in the list must be
     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)}
     * must not throw a {@code ClassCastException} for any elements
     * {@code e1} and {@code e2} in the list).
     *
     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
     * not be reordered as a result of the sort.
     *
     * <p>The specified list must be modifiable, but need not be resizable.
     *
     * <p>Implementation note: This implementation is a stable, adaptive,
     * iterative mergesort that requires far fewer than n lg(n) comparisons
     * when the input array is partially sorted, while offering the
     * performance of a traditional mergesort when the input array is
     * randomly ordered.  If the input array is nearly sorted, the
     * implementation requires approximately n comparisons.  Temporary
     * storage requirements vary from a small constant for nearly sorted
     * input arrays to n/2 object references for randomly ordered input
     * arrays.
     *
     * <p>The implementation takes equal advantage of ascending and
     * descending order in its input array, and can take advantage of
     * ascending and descending order in different parts of the same
     * input array.  It is well-suited to merging two or more sorted arrays:
     * simply concatenate the arrays and sort the resulting array.
     *
     * <p>The implementation was adapted from Tim Peters's list sort for Python
     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
     * Sorting and Information Theoretic Complexity", in Proceedings of the
     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
     * January 1993.
     *
     * <p>This implementation dumps the specified list into an array, sorts
     * the array, and iterates over the list resetting each element
     * from the corresponding position in the array.  This avoids the
     * n<sup>2</sup> log(n) performance that would result from attempting
     * to sort a linked list in place.
     *
     * @param  <T> the class of the objects in the list
     * @param  list the list to be sorted.
     * @throws ClassCastException if the list contains elements that are not
     *         <i>mutually comparable</i> (for example, strings and integers).
     * @throws UnsupportedOperationException if the specified list's
     *         list-iterator does not support the {@code set} operation.
     * @throws IllegalArgumentException (optional) if the implementation
     *         detects that the natural ordering of the list elements is
     *         found to violate the {@link Comparable} contract
     */
    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Object[] a = list.toArray();
        Arrays.sort(a);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

    /**
     * Sorts the specified list according to the order induced by the
     * specified comparator.  All elements in the list must be <i>mutually
     * comparable</i> using the specified comparator (that is,
     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
     * for any elements {@code e1} and {@code e2} in the list).
     *
     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
     * not be reordered as a result of the sort.
     *
     * <p>The specified list must be modifiable, but need not be resizable.
     *
     * <p>Implementation note: This implementation is a stable, adaptive,
     * iterative mergesort that requires far fewer than n lg(n) comparisons
     * when the input array is partially sorted, while offering the
     * performance of a traditional mergesort when the input array is
     * randomly ordered.  If the input array is nearly sorted, the
     * implementation requires approximately n comparisons.  Temporary
     * storage requirements vary from a small constant for nearly sorted
     * input arrays to n/2 object references for randomly ordered input
     * arrays.
     *
     * <p>The implementation takes equal advantage of ascending and
     * descending order in its input array, and can take advantage of
     * ascending and descending order in different parts of the same
     * input array.  It is well-suited to merging two or more sorted arrays:
     * simply concatenate the arrays and sort the resulting array.
     *
     * <p>The implementation was adapted from Tim Peters's list sort for Python
     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
     * Sorting and Information Theoretic Complexity", in Proceedings of the
     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
     * January 1993.
     *
     * <p>This implementation dumps the specified list into an array, sorts
     * the array, and iterates over the list resetting each element
     * from the corresponding position in the array.  This avoids the
     * n<sup>2</sup> log(n) performance that would result from attempting
     * to sort a linked list in place.
     *
     * @param  <T> the class of the objects in the list
     * @param  list the list to be sorted.
     * @param  c the comparator to determine the order of the list.  A
     *        {@code null} value indicates that the elements' <i>natural
     *        ordering</i> should be used.
     * @throws ClassCastException if the list contains elements that are not
     *         <i>mutually comparable</i> using the specified comparator.
     * @throws UnsupportedOperationException if the specified list's
     *         list-iterator does not support the {@code set} operation.
     * @throws IllegalArgumentException (optional) if the comparator is
     *         found to violate the {@link Comparator} contract
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        Object[] a = list.toArray();
        Arrays.sort(a, (Comparator)c);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }


    /**
     * Searches the specified list for the specified object using the binary
     * search algorithm.  The list must be sorted into ascending order
     * according to the {@linkplain Comparable natural ordering} of its
     * elements (as by the {@link #sort(List)} method) prior to making this
     * call.  If it is not sorted, the results are undefined.  If the list
     * contains multiple elements equal to the specified object, there is no
     * guarantee which one will be found.
     *
     * <p>This method runs in log(n) time for a "random access" list (which
     * provides near-constant-time positional access).  If the specified list
     * does not implement the {@link RandomAccess} interface and is large,
     * this method will do an iterator-based binary search that performs
     * O(n) link traversals and O(log n) element comparisons.
     *
     * @param  <T> the class of the objects in the list
     * @param  list the list to be searched.
     * @param  key the key to be searched for.
     * @return the index of the search key, if it is contained in the list;
     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
     *         <i>insertion point</i> is defined as the point at which the
     *         key would be inserted into the list: the index of the first
     *         element greater than the key, or <tt>list.size()</tt> if all
     *         elements in the list are less than the specified key.  Note
     *         that this guarantees that the return value will be &gt;= 0 if
     *         and only if the key is found.
     * @throws ClassCastException if the list contains elements that are not
     *         <i>mutually comparable</i> (for example, strings and
     *         integers), or the search key is not mutually comparable
     *         with the elements of the list.
     */
    public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }

1.5.2、默认方法

可以为接口方法提供一个默认实现类,必须用default修饰符标记这样一个方法:

默认方法的一个重要用法就是接口演化

类与对象03

1.5.3、解决默认方法冲突

如果先在一个接口中将一个方法定义为默认方法,然后又在超类中或另一个接口中定义了同样的方法,会发生什么情况?

规则如下:

  1. 超类优先。如果超类提供了一个具体方法,同名而且具有相同参数类型的默认方法会被忽略。
  2. 接口冲突。如果一个超接口提供了一个默认方法,另外一个接口提供了一个同名且参数类型(无论是否是默认参数)相同的方法,必须覆盖这个方法来解决冲突

类实现两个接口(一个接口中含有默认方法)存在方法冲突

Person接口

public interface Person {
    
    String getName() ;
}

Named接口(含有默认方法)

public interface Named {

    default String getName(){
        return getClass().getName()+"_"+hashCode();
    }
}

实现

类与对象03

public class Student implements  Person,Named {

    //类会继承Person和Named接口提供的两个不一致的getName方法。
    //并不是从中选择一个,Java编译器会报告一个错误,让程序员来解决这个二义性。
    //只需要在Student类中提供一个getName方法。在这个方法中,可以选择两个冲突中的一个
    @Override
    public String getName() {
        return Named.super.getName();
    }
}


类实现两个接口存在方法冲突

如果两个接口都没有为共享方法提供默认实现,这里不存在冲突。

实现类可以有两个选择:实现这个方法,或者干脆不实现

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/31 0031  13:55
 */
public interface Person {

    String getName() ;
}


public interface Named {

   String getName();
}
////////////////////////////////
public class Student implements  Person,Named {


    @Override
    public String getName() {
        return null;
    }
}


1.5、接口举例

1.5.1、Comparator接口

可以对一个字符串数组排序,因为String类实现了Comparable<String>类,而且String.CompareTo方法可以按字典顺序比较字符串

 /**
     * Compares two strings lexicographically.
     * The comparison is based on the Unicode value of each character in
     * the strings. The character sequence represented by this
     * {@code String} object is compared lexicographically to the
     * character sequence represented by the argument string. The result is
     * a negative integer if this {@code String} object
     * lexicographically precedes the argument string. The result is a
     * positive integer if this {@code String} object lexicographically
     * follows the argument string. The result is zero if the strings
     * are equal; {@code compareTo} returns {@code 0} exactly when
     * the {@link #equals(Object)} method would return {@code true}.
     * <p>
     * This is the definition of lexicographic ordering. If two strings are
     * different, then either they have different characters at some index
     * that is a valid index for both strings, or their lengths are different,
     * or both. If they have different characters at one or more index
     * positions, let <i>k</i> be the smallest such index; then the string
     * whose character at position <i>k</i> has the smaller value, as
     * determined by using the &lt; operator, lexicographically precedes the
     * other string. In this case, {@code compareTo} returns the
     * difference of the two character values at position {@code k} in
     * the two string -- that is, the value:
     * <blockquote><pre>
     * this.charAt(k)-anotherString.charAt(k)
     * </pre></blockquote>
     * If there is no index position at which they differ, then the shorter
     * string lexicographically precedes the longer string. In this case,
     * {@code compareTo} returns the difference of the lengths of the
     * strings -- that is, the value:
     * <blockquote><pre>
     * this.length()-anotherString.length()
     * </pre></blockquote>
     *
     * @param   anotherString   the {@code String} to be compared.
     * @return  the value {@code 0} if the argument string is equal to
     *          this string; a value less than {@code 0} if this string
     *          is lexicographically less than the string argument; and a
     *          value greater than {@code 0} if this string is
     *          lexicographically greater than the string argument.
     */
    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

假设我们希望按长度递增的顺序对字符串进行排序,而不是按典顺序进行排序。肯定不能让String类用两种不同的方式实现CompareTo方法。

要处理这种情况,Arrays.sort方法还有第二个版本,有一个数组和一个比较器(comparator)作为参数,比较器是实现了Comparator接口的类的实例

@FunctionalInterface
public interface Comparator<T> {
    /**
     * Compares its two arguments for order.  Returns a negative integer,
     * zero, or a positive integer as the first argument is less than, equal
     * to, or greater than the second.<p>
     *
     * In the foregoing description, the notation
     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
     * <i>expression</i> is negative, zero or positive.<p>
     *
     * The implementor must ensure that <tt>sgn(compare(x, y)) ==
     * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
     * implies that <tt>compare(x, y)</tt> must throw an exception if and only
     * if <tt>compare(y, x)</tt> throws an exception.)<p>
     *
     * The implementor must also ensure that the relation is transitive:
     * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
     * <tt>compare(x, z)&gt;0</tt>.<p>
     *
     * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
     * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
     * <tt>z</tt>.<p>
     *
     * It is generally the case, but <i>not</i> strictly required that
     * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  Generally speaking,
     * any comparator that violates this condition should clearly indicate
     * this fact.  The recommended language is "Note: this comparator
     * imposes orderings that are inconsistent with equals."
     *
     * @param o1 the first object to be compared.
     * @param o2 the second object to be compared.
     * @return a negative integer, zero, or a positive integer as the
     *         first argument is less than, equal to, or greater than the
     *         second.
     * @throws NullPointerException if an argument is null and this
     *         comparator does not permit null arguments
     * @throws ClassCastException if the arguments' types prevent them from
     *         being compared by this comparator.
     */
    int compare(T o1, T o2);
}

要按长度比较字符串,可以如下定义一个实现Comparator<String>的类

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/19 0019  19:08
 */
public class LenghtComparator implements Comparator<String> {

    //按照字符串的长度进行比较
    @Override
    public int compare(String o1, String o2) {
        return o1.length()-o2.length();
    }

    public static void main(String[] args) {
        LenghtComparator lenghtComparator = new LenghtComparator();
        String[] str = {"a","EXE","123","CERWERR","1232"};
        Arrays.sort(str,lenghtComparator);
        System.out.println(Arrays.toString(str));
    }
}

1.5.2、Cloneable接口

深拷贝与浅拷贝

类与对象03

Clone方法时Object的一个protected方法,这说明你的代码不能直接调用这个方法;只有Employee类可以克隆Employee对象

想想看Object类是如何实现Clone。它对于这个对象一无所知,所以只能逐个域的进行拷贝。如果对象中的所有数据域都是数值或其他基本类型,拷贝这些域没有任何问题。但是如果对象包含子对象的引用,拷贝域就会得到相同子对象的另一个引用,这样一来,原对象和克隆对象仍然会共享一些信息

浅拷贝有什么影响吗?如果原对象和浅克隆对象共享的子对象是不可变的,那么这种共享就是安全的。如果子对象属于一个不可变的类,入String,就是这种情况。



对于每一各类,需要确定:

  1. 默认的clone方法是否满足要求;
  2. 是否可以在可变的子对象上调用clone来修补默认的clone方法
  3. 是否不改使用clone

实际上第3个选项时默认选项,如果选择第1项或第2项,类必须:

  1. 实现Cloneable接口
  2. 重新定义clone方法,并指定public访问修饰符

Object中的Clone

Object中的Clone

为什么Object中的clone方法的修饰符为default

为了安全吧。jdk的克隆是要实现空接口Cloneable的,我们也要定义具体实现的clone方法。如果简单从Object继承克隆,就是浅克隆,但很多时候我们要的是深克隆。一句话,clone方法需要自己定义,这也要求编码人员有基本的知识储备。

创造并返回一个对象的拷贝。 拷贝的准确含义取决于这个类、

从上面对clone方法的注解可知clone方法的通用约定:对于任意一个对象x,表达式①x.clone != x将会是true;表达式②x.clone().getClass()==x.getClass()将会是true,但不是绝对的;表达式③x.clone().equals(x)将会是true,但是这也不是绝对的。

从源代码可知,根类Object的clone方法是用protected关键字修饰,这样做是为避免我们创建每一个类都默认具有克隆能力

    protected native Object clone() throws         CloneNotSupportedException;

Cloneable接口

一个类实现Cloneable接口表明Object.clone()方法允许进行深拷贝;

在一个没有实现Cloneable的接口的类上调用clone方法将导致CloneNotSupportException异常。

通常,类实现了这个接口应该重写Object.clone(这个方法在Object中是protected修饰的),重写时方法应改为Public

这个接口是不包含方法的;Cloneable接口是Java提供的一组标记接口。应该记得,Comparable等接口的通常用途是确保一个类实现或一组特定的方法;标记接口不包含任何方法;它唯一的作用是允许在类型查询中使用instanceOf

因此,

public interface Cloneable {
}
  @Override
    public Employee clone() throws CloneNotSupportedException {
        //调用Object.clone
        Employee cloned = (Employee)super.clone();
        //克隆可变的域
        cloned.setHireDay((Date)hireDay.clone());
        return cloned;
    }

2、内部类

在Java中,允许在一个类的内部定义类,这样的类被称作 内部类,这个内部类所在的类称作外部类

根据内部类的位置,修饰符合定义方式的不同,内部了可以分为4种形式: 成员内部类局部内部类静态内部类匿名内部类

2.0、为什么使用内部类

类与对象03

类与对象03

2.1、内部类基础

当我们创建一个内部类的时候,它就无形中就与外围类有了一种联系,依赖于这种联系,它就可与无限制的访问外围类的元素

package CoreJavaColume.Chapter06;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/31 0031  14:53
 */
public class OuterClass {
    private String name ;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }



    class InnerClass{
        public InnerClass(){
            name = "chenssy";
            age = 23;
        }

        public  void display(){
            System.out.println("name :"+getName()+"  ;age: "+getAge());
        }
    }

    public static void main(String[] args) {

        //构建外部类
        OuterClass outerClass = new OuterClass();

        //创建外部类的内部类
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();

        innerClass.display();
    }
}

内部类可以访问外部类中的成员变量和属性内部类InnerClass可以对外围类OuterClass的属性进行无缝的访问,尽管它是private的属性。这时因为当我们在创建某个外围类的内部类是,此时内部类对象必定会捕获一个指向那个外围类对象的引用,只要我们在访问外围类的成员时,就会用这个引用来选择外围类的成员

引用内部类:OuterClassName.InnerClassName.

同时如果我们需要创建某个内部类对象,必须要利用外部类的对象通过.new来创建内部类:OuterClassName,InnerCkass innerClass = outerClass.new InnerClass();

对外部类的引用:OuterClassName.this

package CoreJavaColume.Chapter06;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/31 0031  14:53
 */
public class OuterClass {


    public  void display(){
        System.out.println("OuterClass.....");
    }
    

    class InnerClass{
        public OuterClass getOuterClass(){
            return OuterClass.this;
        }
    }

    public static void main(String[] args) {

        //构建外部类
        OuterClass outerClass = new OuterClass();

        //创建外部类的内部类
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();

        //生成外部类
        innerClass.getOuterClass().display();
    }
}

到这里我们需要明确一点,内部类是一个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。

对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个Class文件:OuterClass.classOuterClass$InnerClass.class


在Java中内部类主要分为:成员内部类,局部内部类,匿名内部类,静态内部类

2.2、成员内部类

在一个类中除了可以定义成员变量,成员方法,还可以定义类。

在成员内部类中,可以访问外部类的所有成员,包括成员变量和成员方法;在外部类中,同样也可以访问内部类的成员和遍历。


成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问

在成员内部类中药注意两点:

  1. 成员内部类中不能存在任何static的变量和方法
  2. 成员内部类是依附于外围类的,所以只要先创建了外围类才能够创建内部类
package CoreJavaColume.Chapter06;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/31 0031  14:53
 */
public class OuterClass {
    private String str;

    public void outerDisplay(){
        System.out.println("outerClass...");
    }

    public class InnerClass{
        public void innerDisplay(){
            //使用外围类的属性
            str = "chenssy...";
            System.out.println(str);
            //使用外围类的方法
            outerDisplay();
        }
    }

    /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
    public InnerClass getInnerClass(){
        return new InnerClass();
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.getInnerClass();
        inner.innerDisplay();
    }
}

推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时。

2.3、局部内部类

有这样一种内部类,它是嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

在局部内部类中,局部内部类可以访问外部类的所有成员变量和方法,

==而局部内部类中的变量和方法确只能在创建该局部内部类的方法中进行访问=

//定义在作用域内
public class Parcel5 {
    private void internalTracking(boolean b){
        if(b){
            /////定义在作用域中成员内部类///
            class TrackingSlip{
                private String id;
                TrackingSlip(String s) {
                    id = s;
                }
                String getSlip(){
                    return id;
                }
            }
            /////定义在作用域中成员内部类///
            TrackingSlip ts = new TrackingSlip("chenssy");
            String string = ts.getSlip();
        }
    }

    public void track(){
        internalTracking(true);
    }

    public static void main(String[] args) {
        Parcel5 parcel6 = new Parcel5();
        parcel6.track();
    }

2.4、静态内部类

所谓静态内部类,就是使用static关键字修饰的成员内部类

与成员内部类相比,在形式上,静态内部类只是在内部类前增加了static关键字;但在功能上,静态内部类只能访问外部类的静态成员

类与对象03

package CoreJavaColume.Chapter06;

public class OuterClass {
    private String sex;
    public static String name = "chenssy";

    /**
     *静态内部类
     */
    static class InnerClass1{
        /* 在静态内部类中可以存在静态成员 */
        public static String _name1 = "chenssy_static";

        public void display(){
            /*
             * 静态内部类只能访问外围类的静态成员变量和方法
             * 不能访问外围类的非静态成员变量和方法
             */
            System.out.println("OutClass name :" + name);
        }
    }

    /**
     * 非静态内部类
     */
    class InnerClass2{
        /* 非静态内部类中不能存在静态成员 */
        public String _name2 = "chenssy_inner";
        /* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */
        public void display(){
            System.out.println("OuterClass name:" + name);
        }
    }

    /**
     * @desc 外围类方法
     * @author chenssy
     * @data 2013-10-25
     * @return void
     */
    public void display(){
        /* 外围类访问静态内部类:内部类. */
        System.out.println(InnerClass1._name1);
        /* 静态内部类 可以直接创建实例不需要依赖于外围类 */
        new InnerClass1().display();

        /* 非静态内部的创建需要依赖于外围类 */
        OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
        /* 方位非静态内部类的成员需要使用非静态内部类的实例 */
        System.out.println(inner2._name2);
        inner2.display();
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.display();
    }
}
//----------------
//        Output:
//        chenssy_static
//        OutClass name :chenssy
//        chenssy_inner
//        OuterClass name:chenssy

2.5、匿名内部类

匿名内部类其实就是没有名称的内部类

在调用包含接口抽象类类型参数的方法是,通常为了简化代码,不会创建一个接口的实现类作为参数传入,而是直接通过匿名内部类的形式传入一个接口类型参数,在匿名内部类中直接完成方法的实现。

package CoreJavaColume.Chapter06;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/31 0031  14:53
 */
public class OuterClass {

    /**
     * 通过匿名内部类返回一个类
     * @param num
     * @param str2
     * @return
     */
    public InnerClass getInnerClass(final int num,String str2){
        /////////
        return new InnerClass(){//其中InnerClass可以为接口也可以为抽象类
            int number = num + 3;
            public int getNumber(){
                return number;
            }
        };        /* 注意:分号不能省 */
    }

    public static void main(String[] args) {
        OuterClass out = new OuterClass();
        InnerClass inner = out.getInnerClass(2, "chenssy");
        System.out.println(inner.getNumber());
    }                                       
}

interface InnerClass {
    int getNumber();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIAhXapo-1580457185948)(images/26.png)]

-------------------------------------- 2020年1月31日15:52:32

相关标签: Java基础整理