Java基础

Java基础

1.重载和重写有什么区别

重写的规则:

  • 参数列表与被重写方法的参数列表必须完全相同。
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
  • 子类在重写父类抛出异常的方法时,要么不抛出异常,要么抛出与父类方法相同的异常或该异常的子类
  • 构造方法不能被重写。
  • 如果不能继承一个方法,则不能重写这个方法。
class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      System.out.println("狗可以跑和走");
   }
   public void bark(){
      System.out.println("狗可以吠叫");
   }
}
 
public class TestDog{
   public static void main(String args[]){
      Animal a = new Animal(); // Animal 对象
      Animal b = new Dog(); // Dog 对象
 
      a.move();// 执行 Animal 类的方法
      b.move();//执行 Dog 类的方法
      b.bark(); 
   }
}

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。

每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。

最常用的地方就是构造器的重载。

重载规则:

  • 被重载的方法必须改变参数列表(参数个数或类型不一样);
  • 被重载的方法可以改变返回类型;
  • 被重载的方法可以改变访问修饰符;
  • 被重载的方法可以声明新的或更广的检查异常;
  • 方法能够在同一个类中或者在一个子类中被重载。
  • 无法以返回值类型作为重载函数的区分标准

重写与重载之间的区别

区别点重载方法重写方法
参数列表必须不同必须相同
返回类型可以不同也可以不同,但必须是父类的衍生类
异常可以不同可以减少或删除,但不能抛出新的或更广的异常
访问可以不同不能做更严格的限制,但可以降低限制

总结:

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

  • 方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
  • 方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
  • 方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

在Java中,重写与重载都是与同一方法的不同表现形式,区别在于:

  • 子父级关系不同: 重写是针对子级和父级的不同表现形式,而重载是在同一类中的不同表现形式。
  • 概念不同: 同上方定义。
2. java四种访问权限
访问权限本类本包的类子类非子类的外包类
public
protected
default
private
3. 异常(Exception 和 Error 的区别)

Exception 泛指的是 异常 ,Exception 主要分为两种,一种是编译期出现的异常,称为 checkedException ,一种是程序运行期间出现的异常,称为 unchecked Exception。常见的checkedException有IOException,uncheckedException 统称为 RuntimeException,常见的有 NullPonterExceptionArrayIndexOutoofBoundException等。Exception可以被捕获。

Error 是指程序运行过程中出现的错误,通常情况下会造成程序的崩溃,Error 通常是不可恢复的,Error 不能被捕获。

4.Super 关键字的使用

当需要在子类中调用父类的被重写方法时,要使用 super 关键字。

5. this关键字的使用

this关键字指向的是当前对象的引用

this.属性名称:指的是访问类中的成员变量,用来区分成员变量和局部变量(重名问题)有参构造里会用到。

this.方法名称:用来访问本类的成员方法

this():访问本类的构造方法

()中可以有参数的 如果有参数 就是调用指定的有参构造

注意事项:
1.this() 不能使用在普通方法中 只能写在构造方法中
2.必须是构造方法中的第一条语句

6.抽象类和接口的区别

接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。

抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。

人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.

所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。

抽象类与接口都是Java中的关键字,抽象类与接口中都允许进行方法的定义,而不用实现具体的方法。抽象类与接口都允许被继承,它们广泛的应用于JDK和框架的源码中,来实现多态和不同的设计模式。

不同点在于:

  • 抽象级别不同:类、抽象类、接口其实是三种不同的抽象级别,抽象程度依此是 接口 > 抽象类 > 类。在接口中,只允许进行方法的定义,不允许有方法的实现,抽象类中可以进行方法的定义与实现;而类中只允许进行方法的实现,方法的定义是不允许在方法后添加{}
  • 使用的关键字不同:类使用 class 来表示;抽象类使用 abstract class 来表示;接口使用 interface 来表示;
  • 变量:接口中定义的变量只能是公共的静态常量,抽象类中的变量是普通变量。
  • 方法:接口中的方法不能是private。
  • 实现:抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
  • 构造方法:1)接口不能有构造方法,抽象类可以有。
    2)接口不能有方法体,抽象类可以有。
    3)接口不能有静态方法,抽象类可以有。
    4)在接口中凡是变量必须是public static final,而在抽象类中没有要求。
7.什么是构造方法

构造函数(构造器、构造方法):构造函数是一种特殊的函数。其主要功能是用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

8.==、equlas和hashcode

==:是Java中一种操作符

对于 基本数据类型 来说, == 判断的是两边的 是否相等

对于 引用类型 来说, == 判断的是两边的 引用 是否相等,也就是判断两个对象是否指向了同一块内存区域。(内存地址是否相等)

equlas:是 Java 中所有对象的父类,即 object 类定义的一个方法。它只能比较对象,它表示的是引用双方的值是否相等。

9. String中的 equals 是如何重写的

String 代表的是 Java 中的 字符串 ,String类比较特殊,它整个类都是被 final 修饰的,也就是说,String 不能被任何类继承, 任何 修改 String 字符串的方法都是创建一个新的字符串。

String 重写了object 的 equals 方法

public boolean equals(Object anObject) {
    	// 先判断 `引用` 是否相等
        if (this == anObject) {
            return true;
        }
    	// 再判断,比较的对象是否是String的实例
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            // 再判断,字符串长度是否相等
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                // 逐个比较字符
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

String.intern() 源码

public native String intern();

在JDK1.7及以后调用 intern方法是判断运行是常量池中是否有指定的字符串,如果没有,就把字符串添加到常量池中,并返回常量池中的对象。

public static void main(String[] args) {
        String s1 = "aaa";
    	// 此字符串也会用到
        String s2 = "aa" + new String("a");
        String s3 = new String("aaa");

        // true s1 字符串创建出来就已经在常量池中了
        System.out.println(s1.intern() == s1);

        // false s1 返回的是常量池中的对象,s2 返回的是堆中的对象
        System.out.println(s1 == s2);

        // true s3对象虽然在堆中创建了一个对象,但返回的是常量池中“aaa”的对象
        System.out.println(s3.intern() == s1);
    }
10. 为什么重写 equals 方法必须重写 hashcode 方法

equals 方法和 hashCode 都是 Object 中定义的方法,它们经常被一起重写。

equals 方法是用来比较对象大小是否相等的方法,hashcode 方法是用来判断每个对象hash值的一种方法。如果只重写 equals 方法而不重写 hashcode 方法,很可能会造成两个不同的对象,它们的hashcode也相等,造成冲突。

hashCode官方定义:

  • 如果在 Java 运行期间对同一个对象调用hashCode 方法后,无论调用多少次,都应该返回相同的 hashCode,但是在不同的 Java 程序中,执行 hashCode 方法返回的值可能不一致。
  • 如果两个对象的equals相等,那么hashcode必须相等
  • 如果两个对象的 equals不相等,那么 hashcode 也可能相同,所以需要重写hashCode 方法,因为你不知道hashCode 的底层架构,所以你需要重写hashcode方法,来为不同的对象生成不同的 hashcode值,这样能够提高不同对象的访问速度。
  • hashcode通常是将地址转化为整数来实现的。
11. String、StringBuilder 和 StringBuffer 有什么区别

String 特指的是 Java 中的字符串,String 类位于 Java.lang包下,String 类是由 final 修饰的,String 字符串一旦创建就不能被修改,任何对 String 字符串进行的修改操作都相当于重新创建了一个字符串。String 字符串的底层使用 StringBuilder 来实现。

StringBuilder 位于 java.until 包下,StringBuilder 是一非线程安全的容器,StringBuilder 的 append 方法常用于字符串拼接,它的拼接效率比 String 中 + 号的拼接效率高。StringBuilder 一般不用于并发环境。

StringBuffer 位于 java.until 包下,StringBuffer 是一个线程安全的容器,多线程场景下一般使用 StringBuffer 用作字符串的拼接。

StringBuilder 和 StringBuffer 都是继承于 AbstractStringBuilder 类,都实现了常规操作。

		String s1 = "aaa";
        String s2 = "bbb" + "ccc";
        String s3 = s1 + "bbb";
        String s4 = new String("aaa");

分别创建了几个对象?

  • 首先第一个问题,s1 创建了几个对象。字符串在创建对象时,会在常量池中看有没有 aaa 这个字符串;如果没有此时还会在常量池中创建一个;如果有则不创建。我们默认是没有的情况,所以会创建一个对象。下同。

  • 那么 s2 创建了几个对象呢?是两个对象还是一个对象?我们可以使用 javap -c 看一下反汇编代码

    public class com.sendmessage.api.StringDemo {
      public com.sendmessage.api.StringDemo();
        Code:
           0: aload_0
           1: invokespecial #1                  // 执行对象的初始化方法
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // 将 String aaa 执行入栈操作
           2: astore_1													# pop出栈引用值,将其(引用)赋值给局部变量表中的变量 s1
           3: ldc           #3                  // String bbbccc
           5: astore_2
           6: return
    }
    

    ​ 编译器做了优化 String s2 = “bbb” + “ccc” 会直接被优化为 bbbccc。也就是直接创建了一个 bbbccc 对象。

    javap 是 jdk 自带的反汇编工具。它的作用就是根据 class 字节码文件,反汇编出当前类对应的 code 区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息。

    javap -c 就是对代码进行反汇编操作。

    下面来看 s3,s3 创建了几个对象呢?是一个还是两个?还是有其他选项?我们使用 javap -c 来看一下

    我们可以看到,s3 执行 + 操作会创建一个 StringBuilder 对象然后执行初始化。执行 + 号相当于是执行 new StringBuilder.append() 操作。所以

  String s3 = s1 + "bbb";
  
  ==
    
  String s3 = new StringBuilder().append(s1).append("bbb").toString();
  
  // Stringbuilder.toString() 方法也会创建一个 String 
  
  public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
  }

所以 s3 执行完成后,相当于创建了 3 个对象。

下面来看 s4 创建了几个对象,在创建这个对象时因为使用了 new 关键字,所以肯定会在堆中创建一个对象。然后会在常量池中看有没有 aaa 这个字符串;如果没有此时还会在常量池中创建一个;如果有则不创建。所以可能是创建一个或者两个对象,但是一定存在两个对象。

12. byte的取值范围是多少,怎么计算出来的

byte的取值范围是 -128 - 127 之间, 一共是256。

一个byte类型在计算机中占据一个字节,那么就是8bit。

Java中用补码 来表示二进制,补码的最高位是符号位,最高位用0表示正数,1表示负数,正数的补码是其本身 ,由于最高位是符号位,所以正数表示的就是0111 1111,也就是127。最大负数是 1111 1111,这其中会涉及到两个 0,一个 +0, 一个 -0, +0 归为正数,也就是 0 , -0 归为负数,也就是 -128,所以byte的范围是-128 - 127。

13. HashMap 和 HashTable 的区别

相同的:HashMap和HashTable都是基于哈希表实现的,其内部每个元素都是 key-value 键值对,HashMap 和 HashTable 都实现了Map、Cloneable、Serializable 接口

不同点

  • 父类不同:HashMap 继承了 AbstractMap 类, 而 HashTable 继承了 Dictionary 类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziWyfr4y-1607244852687)(D:\Doc\文档图片\1598704500236.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Reub4kdC-1607244852699)(D:\Doc\文档图片\1598704554215.png)]

  • 空值不同:HashMap 允许空 key 和 value 值, HashTable 不允许空的 key 和 value 值。HashMap 会把 Null key 当作普通 key 对待。不允许 null key 重复。

    NullPointerException if the key or value is null

    HashTable 源码:

* @exception  NullPointerException  if the key or value is
     *               <code>null</code>
     * @see     Object#equals(Object)
     * @see     #get(Object)
     */
    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
    	// key为null,key.hashCode()报NullPointerException
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
  • 线程安全性:HashMap 不是线程安全的,如果多个外部操作同时修改 HashMap 的数据结构 如 add 或者 delete,必须进行同步操作,仅仅对 key 或者 value 的修改不是改变数据结构的操作。可以选择构造线程安全的 Map 比如 Collections.synchronizedMap 或者是 ConcurrentHashMap。而 HashTale 本身就是线程安全的容器。
  • 性能方面:虽然 HashMap 和 HashTable 都是基于 单链表 的,但是 Hash Map 进行put 或者 get 操作,可以达到常数时间的性能;而 HashTable 的 put 和 get 操作都是加了 synchronized 锁的,所以效率很低。
  • 初始容量不同:HashTable 的初始长度是11,之后每次扩充容量变为之前的 2n+1(n为上一次的长度)而 HashMap 的初始长度为 16,之后每次扩充变为原来的两倍。创建时,如果给定了容量初始值,那么 HashTable 会直接使用你给定的大小,而 HashMap 会将其扩充位2的幂次方。
14. HashMap 和 HashSet 的区别

HashSet 继承于 AbstrctSet 接口,实现了 Set, Cloneable, java.io.Serializable 接口。 HashSet 不允许集中出现重复的值。HashSet 底层其实是 HashMap,所有对 HashSet 的操作其实就是对 HashMap 的操作。所以 HashSet 也不保证集合的顺序,也不是线程安全的容器。

15. HashMap 的底层结构

JDK1.7 中,HashMap 采用 位桶 + 链表 的实现,即使用 链表 来处理冲突,同一 hash 值的链表都存储在一个数组中。但是当位于一个桶中的元素较多,即 hash 值相等的元素较多时,通过 key 值依次查找的效率较低。

所以,与 JDK1.7 相比,JDK1.8 在地层结构方面做了一些改变,当每一桶中元素大于 8 的时候,会转变位红黑树,目的是优化查询效率。

16. HashMap 的长度为什么是 2 的幂次方

hash%length == (n - 1)& hash,前提是 length HashMap的长度是 2 的幂次方。如果不是 2 的幂次方,HashMap 的碰撞机率会增大

17. HashMap 多线程操作导致死循环问题

因为 HashMap 不是一个线程安全的容器,所以并发场景下推荐使用 ConcurrentHashMap,或者使用线程安全的 HashMap,使用 Collections 包下的线程安全的容器,比如

HashMap<Object, Integer> hashMap = new HashMap<>();
Collections.synchronizedMap(hashMap);

还可以使用 HashTable,它也是线程安全的容器,基于 key -value 存储,经常用 HashMap 和 HashTable 做比较就是因为 HashTable 的数据结构和 HashMap 相同。

上面效率最高的就是 ConcurrentHashMap。

18. 讲一下 HashMap put 的过程

key值不等的时候,可能hashcode可能相等

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
    	// 如果table 为null 或者 没有为table分配内存,就resize
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
    	// 判断传入的key的hashcode是否已存在,(n - 1) & hash用来计算下标,
    	// 不存在就直接赋值。
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
    	// key的hashcode已存在
        else {
            Node<K,V> e; K k;
            // hash值与key都相等的情况,重新对同一个key赋值
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            // 当前节点是否已是红黑树的节点
            else if (p instanceof TreeNode)
                // 采用红黑树的方式存储
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            // 出现hash冲突
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        // 在表尾插入
                        p.next = newNode(hash, key, value, null);
                        // 新增节点后,如果这个节点到达阀值,就进入treeifyBin
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    // hash值与key值相等时,就退出循环
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    // 更新 p 指向下一个节点
                    p = e;
                }
            }
            // map中含有旧值,返回旧值
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
    	// map调整次数 + 1
        ++modCount;
    	// 键值对的数量达到阀值,需要扩容
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
if (p.hash == hash &&
     ((k = p.key) == key || (key != null && key.equals(k))))

为什么先判断hash值,再判断对象是否相等。

hash值不相等,对象一定不相等;hash值相等,对象不一定相等。

根据这条理论依据,所以先判断hash值;key的equals方法,你可能对他进行了重写,如果逻辑很复杂,先判断可能影响效率。

19. ConcurrentHashMap 底层实现

ConcurrentHashMap 是线程安全的Map, 它也是高并发场景下的首选数据结果,ConcurrentHashMap 底层是使用 分段锁 来实现。

20. Integer 缓存池

Integer 缓存池也就是 IntegerCache,它是Integer 的静态内部内类。

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

它的默认值用于缓存 -128 - 127 之间的数字,如果有 -128 - 127 之间的数字的话,使用 new Integer 不用创建对象,会直接从缓存池中取,此操作会减少堆中对象的分配,有利于提高程序的运行效率。

例如创建一个 Integer a = 24, 其实是调用Integer 的 valueOf,可以通过反编译得出这个结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRA3WrkF-1607244852707)(D:\Doc\文档图片\1598767261425.png)]

如果在指定的缓存池范围内的话,会直接返回缓存的值而不用创建新的 Integer 对象。

缓存的大小可以使用 XX:AuotBoxCacheMax 来指定,在 VM 初始化时,java.lang.Integer.IntegerCache.high 属性会设置和保存在 sum.misc.VM 的私有系统属性中。

21. Arrays.asList 获得的 List 应该注意什么

Arrays.asList 是 Array 中的一个静态方法,它能够实现把数组转换成为 List 序列,需要注意几点:

  • Arrays.asList 转换完成后的 List 不能再进行结构化的修改,什么是结构化的修改?就是不能在进行任何 List 元素的增加或者减少的操作。

Java中的基础数据类型(byte,short,int,long,float,double,boolean)是不支持使用 Arrays.asList 方法去转换的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYKBqzca-1607244852712)(D:\Doc\文档图片\1599120664102.png)]

这个私有内部类并不提供add与remove等方法。

22. Collection 和 Collections 的区别

Collection 和 Collections 都是位于 java.util 包下的类。Collection 是集合的父类,它是一个顶级接口,大部分抽象类比如说 AbstractListAbstractSet 都是继承了Collection 类,Collection 类只定义一节标准方法比如说add、remove、set、equals 等,具体的方法由抽象类或者实现类去实现。

Collections 是集合类的工具类,Collections提供了一些工具的基本使用

  • sort 方法:对当前集合进行排序,实现Comparable 接口的类,只能使用一种排序方案,这种方案叫做自然比较,比如实现线程安全的容器 Collections.synchronizedList、Collections.synchronizedMap 等
  • reverse 反转,使用 reverse 方法可以根据元素的自然顺序对指定列表按降序进行排序。
  • fill,使用指定元素替换指定列表中的所有元素。

方法还有很多,Collections不能被实例化,所以Collections 中的方法都是由 Collections.方法名 直接调用,Collections不是静态类,但方法都是静态方法。

23. ArrayList、LinkedList、Vector 的区别

ArrayList、LinkedList、Vector 都是位于 java.util 包下的工具类,它们都实现了 List 接口。

  • ArrayList 的底层是动态数组,它是基于数组的特性而演变出来的,所以ArrayList遍历访问非常快,但是增删比较慢,因为会涉及到数组的拷贝。ArrayList 是一个非线程安全的容器,在并发场景下会会造成问题,如何想使用线程安全的容器的话,推荐使用 Collections.synchronizedList; ArrayList 在扩容会增加 50% 的容量。
  • LinkedList 的底层是双向链表,所以LinkedList 的增加与删除非常快,只需把元素删除,把各自的指针指向新的元素即可。但是 LinkedList 便利比较慢,因为只有每次访问一个元素才能知道下一个元素的地址。LinkedList 也是一个非线程安全的容器,推荐使用 Collections.synchronizedList
  • Vectot 向量是最早出现的集合容器,Vector 是一个线程安全的容器,它的每个方法都粗暴的加上了 synchronized 锁,所以它的增删、便利效率都很低。Vector 在扩容时,它的容量会增加一倍。
24.Java集合有哪些

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1gn9CGlu-1607244852715)(D:\Doc\文档图片\2018102523155144.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AzaP47Aq-1607244852716)(D:\Doc\文档图片\20181025231613150.png)]

Map接口和Collection接口是所有集合框架的父接口

  1. Collection接口的子接口包括:Set接口和List接口。Set中不能包含重复的元素。List是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式。
  2. Map接口的实现类主要有:HashMap、Hashtable、ConcurrentHashMap以及TreeMap等。Map不能包含重复的key,但是可以包含相同的value。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。
  3. Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
  4. List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
  5. Iterator,所有的集合类,都实现了Iterator接口,这是一个用于遍历集合中元素的接口,主要包含以下三种方法:
    hasNext()是否还有下一个元素
    next()返回下一个元素
    remove()删除当前元素
25. 动态代理是基于什么原理

代理一般分为 静态代理动态代理,它们都是代理模式的一种应用,静态代理指的是在程序运行前已经编译好,程序知道由谁来执行代理方法。

而动态代理只有在程序运行期间才能确定,相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

26. 封装、继承和多态

我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是:代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

27. java的命名规则

1、 项目名全部小写

2、 包名全部小写

3、 类名首字母大写,如果类名由多个单词组成,每个单词的首字母都要大写。

如:public class MyFirstClass{}

4、 变量名、方法名首字母小写,如果名称由多个单词组成,每个单词的首字母都要大写。

如:int index=0;

​ public void toString(){}

5、 常量名全部大写

如:public static final String GAME_COLOR=”RED”;

6、所有命名规则必须遵循以下规则:

1)、名称只能由字母、数字、下划线、$符号组成

2)、不能以数字开头

3)、名称不能使用JAVA中的关键字。

4)、坚决不允许出现中文及拼音命名。

7、 属性注释

在每个属性前面必须加上属性注释,注释模板如下:

/** 提示信息 */

private String strMsg = null;

8、 方法注释

在每个方法前面必须加上方法注释,注释模板如下:

/**

* 类方法的详细使用说明

* @param 参数1 参数1的使用说明

* @return 返回结果的说明

* @throws 异常类型.错误代码 注明从此类方法中抛出异常的说明

*/

9、 构造方法注释

在每个构造方法前面必须加上注释,注释模板如下:

/**

* 构造方法的详细使用说明

* @param 参数1 参数1的使用说明

* @throws 异常类型.错误代码 注明从此类方法中抛出异常的说明

*/

10、 方法内部注释

在方法内部使用单行或者多行注释,该注释根据实际情况添加。

如://背景颜色

​ Color bgColor = Color.RED

28. 值传递与引用传递的区别

值传递:是指在调用函数时将实际参数复制一份到函数中,这样的话如何函数对其传过来的形参进行修改,将不会影响到实参。

引用传递:是指在调用函数时将对象的地址直接传递到函数中,如果对其形参进行修改,将影响到实参的值。

29. static 关键字的理解

static 是 Java 中非常重要的关键字, static 表示的概念是 静态的 ,在Java中, static主要用来:

  • 修饰变量,static 修饰的变量称为 静态变量 、也称类变量,类变量属于类所有,对于不同的类来说,static 变量只有一份,static 修饰的变量位于方法区;static 修饰的变量能够直接通过 类名.变量名 来进行访问,不用通过实例化类再使用。
  • 修饰方法, static 修饰的方法称为 静态方法, 静态方法能够直接通过 类名.方法名 来使用,在静态方法内部不能使用非静态属性与方法
  • 修饰代码块,主要分为两种,一种是直接定义在类中,使用 static{} ,这种被称为 静态代码块 ,一种是在类中定义 静态内部类 ,使用 static class ××× 来进行定义。
  • 可以用于静态导包,通过使用 import static ××× 来实现,一般不推荐。
  • static 可以和单例模式一起使用,通过双重检查锁来实现线程安全的单例模式
30. final 关键字的理解

final 是 Java 中的关键字,它表示的意思是 不可变 ,在Java中, final主要用来

  • 修饰类:final 修饰的类是不能被继承,不能被继承的意思就是不能使用 extends 来继承被final修饰的类。
  • 修饰变量:final 修饰的变量不能被修改,不能被修改的意思是有两种,对于基本数据类型来说,final 修饰的变量,其值不能被改变,final 修饰的对象,对象的引用不能被改变,但对象内部的属性可以被修改。final修饰的变量在某种程度上起到了 不可变 的效果,可以用来保护只读数据,尤其是在并发编程中,因为明确的不能在为final变量赋值,有利于减少额为的同步开销。
  • 修饰方法,final修饰的方法不能被重写。
  • final修饰符和Java程序性能优化没有必然联系。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值