栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

java基础知识点总结篇一

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java基础知识点总结篇一

1、什么是面向对象?
网上资料: 面向对象是一种基于面向过程的编程思想,是向现实世界模型的自然延伸,这是一种“万物皆对象”的编程思想。由执行者变为指挥者,在现实⽣生活中的任何物体都可以归一类事物,而一个体都是一类事物的实例。面向对象的编程是以对象为中心,以消息为驱动。
我的回答: 一个实例的所有属性的综合,比如说一个学生,当创建一个学生的对象,那就需要学生的就读学校,就读班级,定位学生的学号,学生的学习成绩,学生的授课老师,这些属性综合起来就可以描述一个学生的群体,这就是一个对象,反正总的一句话,万事万物皆对象。

2、Java语言有哪些特点?
答: 简单性、面向对象、分布性、编译和解释性、稳健性、安全性、可移植性、高性能、多线索性、动态性。

3、JDK、JRE、JVM之间的区别
答: JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。JRE可以让计算机系统运行Java应用程序(Java Application)。JVM是Java虚拟机的缩写,它是一种用于计算设备的规范,是一个虚构出来的计算机,它是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。

4、Java和C++的区别
答: Java语言继承了C++语言的优点,去掉了C++中学习起来比较难的多继承、指针等概念,所以Java语言学习起来更简单,使用起来也更方便。

5、什么是Java程序的主类?应用程序和小程序的主类有何不同?
答: 一个程序中可以有多个类,但只能有一个类是主类。在 Java 应用程序中,这 个主类是指包含 main()方法的类。而在 Java 小程序中,这个主类是一个继承自系统类 JApplet 或 Applet 的子类。应用程序的主类不一定要求是 public 类,但小程序的主类要求必须是 public 类。主类是 Java 程序执行的入口点。

6、构造器Constructor是否可被override
答: 构造器是不能被继承的,因为每个类的类名都不相同,而构造器名称与类名相同,所以根本谈不上继承。又由于构造器不能继承,所以就不能被重写。但是,在同一个类中,构造器是可以被重载的。

7、==和equals⽅法之前的区别
答: 首先equals是一个方法,写在Object超类里面的方法,Object类中的equals方法默认比较地址值,但是一般的java工具类或者包装类中都重写了equals方法,比较内容是否相等。比如说:String、Date、File、包装类等都重写了Object类的equals方法,其中都是比较值相等。
其次,== 是一个比较运算符,返回的就是一个布尔值true,false,如果比较的是基本数据类型变量,比较两个变量的值是否相等。(不一定数据类型相同),如果比较的是引用数据类型变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个地址值

		Integer i = 1234;
        Integer j = Integer.valueOf("1234");
        System.out.println(i == j); // false
        System.out.println(i.equals(j)); // true

        Integer a = 123;
        Integer b = 123;
        System.out.println(a == b);// true
        System.out.println(a.equals(b)); // true
        
        Integer c = 123;
        Integer d = new Integer("123");
        System.out.println(c == d); // false
        System.out.println(c.equals(d)); // true
        
 		Integer e = 123;
        Integer f = Integer.valueOf("123");
        System.out.println(e == f); // true
        System.out.println(e.equals(f)); // true

8、hashCode()与equals()之间的关系
答: hashCode()方法是java中的每一个对象都可以调用的方法,相当于一个独立的指纹信息,由对象导出的一个整型值,可以是负数,具有无规律性。可以利用hashCode来做一些提前的判断,如:、

1、如果两个对象的hashCode不相同,那么这两个对象肯定是不同的对象。
2、如果两个对象的hashCode相同,不代表这两个对象是同一个对象,也可能是两个对象
3、如果两个对象相等,那么他们的hashCode就一定相同

重写hashCode()方法后还需要重写equals方法, 首先是为了提高比较对象的效率,采取重写hashcode方法,先进行hashcode比较,如果不同,那么就没必要在进行equals的比较了,这样就大大减少了equals比较的次数,这对比需要比较的数量很大的效率提高是很明显的,其次,保证在equals相同的情况下hashcode值必定相同,如果重写了equals而未重写hashcode方法,可能就会出现两个没有关系的对象equals相同的(因为equal都是根据对象的特征进行重写的),但hashcode确实不相同的。
两个方法重写后的联系:

1、equals()相等的两个对象,hashcode()一定相等;
2、hashcode()不等,一定能推出equals()也不等;
3、hashcode()相等,equals()可能相等,也可能不等。
4、所以先进行hashcode()判断,不等就不用equals()方法了。
5、但equels是是根据对象的特征进行重写的,有时候特征相同,但hash值不同,也不是一个对象。 所以两个都重写才能保障是同一个对象。

9、final关键字的作⽤是什么?
答: final是一个修饰符(关键字)有三种用法:

1、如果一个类使用了final修饰,那么这个类不可以再被其他类派生,即不可以被继承,可以理解为final与abstract为反义词。
2、如果使用final修饰了变量,那么可以确保的是这个变量在使用的过程中不被改变,另外在声明的初始时候就必须要给变量初始化值。
3、如果使用final修饰方法,这个方法不可以被派生类重写,只有使用权限。

10、String、StringBuffer、StringBuilder的区别
答: String类是不可变类,当一个String对象被创建,则包含在对象中的字符序列是不可改变的,直至对象被销毁;StringBuffer对象代表可变字符串对象,且线程安全;StringBuilder类代表可变字符串对象,且非线程安全

11、重载和重写的区别
答: 重载: 编译时多态、同一个类中同名的方法具有不同的参数列表、不能根据返回类型进行区分(函数调用时不能指定类型信息,编译器不知道要调用的是哪个函数);
重写(覆盖): 运行时多态,子类与父类之间、子类重写父类的方法具有相同的返回类型、更好的访问权限。

12、接口和抽象类的区别
答: 接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。 接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。另外,接口和抽象类在方法上有区别:

1、抽象类可以有构造方法,接口中不能有构造方法。
2、抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
3、抽象类中可以有普通成员变量,接口中没有普通成员变量。 4、抽象类中的抽象方法的访问类型可以是public,protected和默认类型。
5、抽象类中可以包含静态方法,接口中不能包含静态方法。
6、抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static
final类型,并且默认即为public static final类型。
7、一个类可以实现多个接口,但只能继承一个抽象类。二者在应用方面也有一定的区别:接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用,例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的Servlet都继承这个抽象基类,在抽象基类的service方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码。

13、List和Set的区别
答: List 集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引 。 List 集合允许使用重复元素,可以通过索引来访问指定位置的集合元素 。 List 集合默认按元素的添加顺序设置元素的索引。Set集合只能存放无序的,不能重复的数据, Set集合与Collection的用法基本类似,可以这么说,Set集合就是Collection(但Set集合不能存放相同的元素,如果使用add添加相同的元素,add会返回false,且添加的元素也没有添加进去)

14、ArrayList和LinkedList区别
答: 1、数据结构不同 ArrayList是Array(动态数组)的数据结构,LinkedList是Link(链表)的数据结构。2、效率不同 当随机访问List(get和set操作)时,ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。当对数据进行增加和删除的操作(add和remove操作)时,LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。3、适应性不同,ArrayList自由性较低,因为它需要手动的设置固定大小的容量(如果不设置固定的容量大小,那初始化后会自动设置DEFAULT_CAPACITY = 10的大小,如果超过了这个容量大小,会自动扩展为原来的1.5倍),但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。4、主要控件开销不同 ArrayList主要控件开销在于需要在List列表预留一定空间;而LinkList主要控件开销在于需要存储结点信息以及结点指针信息。

15、HashMap和HashTable有什么区别?其底层实现是什么?
答:
相同点: hashmap和Hashtable都实现了map、Cloneable(可克隆)、Serializable(可序列化)这三个接口
HashMap的底层原理:

两者的表面区别:
1、HashMap是非线程安全的,HashTable是使用synchronized实现线程安全的。
2、HashMap的键和值都允许有null值存在,而HashTable则不行。
3、因为线程安全的问题,HashMap效率比HashTable的要高。
4、Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。

两者的底层区别:

1、HashMap的底层数据结构不同: jdk1.7底层都是数组+链表,但jdk1.8 HashMap加入了红黑树
2、添加key-value的hash值算法不同:HashMap添加元素时,是使用自定义的哈希算法,而HashTable是直接采用key的hashCode()
3、实现方式不同:Hashtable 继承的是 Dictionary类,而 HashMap 继承的是 AbstractMap 类。
4、初始化容量不同:HashMap 的初始容量为:16,Hashtable 初始容量为:11,两者的负载因子默认都是:0.75。
5、扩容机制不同:当已用容量>总容量 * 负载因子时,HashMap 扩容规则为当前容量翻倍,Hashtable 扩容规则为当前容量翻倍 +1。
6、支持的遍历种类不同:HashMap只支持Iterator遍历,而HashTable支持Iterator和Enumeration两种方式遍历。
7、迭代器不同:HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。而Hashtable则不会。
8、部分API不同:HashMap不支持contains(Object value)方法,没有重写toString()方法,而HashTable支持contains(Object value)方法,而且重写了toString()方法
9、同步性不同:Hashtable是同步(synchronized)的,适用于多线程环境,而hashmap不是同步的,适用于单线程环境。多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。

最后,一般现在不建议用HashTable:

①是HashTable是遗留类,内部实现很多没优化和冗余。
②即使在多线程环境下,现在也有同步的ConcurrentHashMap替代,没有必要因为是多线程而用HashTable

16、Jdk 7 到Jdk 8 HashMap 发生了什么变化(底层)?
答: 1、hash源码不同
jdk1.7的HashMap类的hash源码:

static int hash(int h) {
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

jdk1.8的HashMap类的hash源码:

 static final int hash(Object key) {
      int h;
      // key.hashCode():返回散列值也就是hashcode
      // ^ :按位异或
      // >>>:无符号右移,忽略符号位,空位都以0补齐
      return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  }

整体来说,JDK7的HashMap类的hash方法实现的整体性能差,而JDK8实现的HashMap类的hash方法性能比较好,因为JDK7的HashMap类的hash方法扰动了四次。

2、底层数据结构不同 java1.8之前的底层数据结构是数组加链表,数组是HashMap的主体,java1.8以后添加了红黑树解决哈希冲突的问题。
3、链表插入方式的不同,在1.7之前,链表元素的插入采用的是头插法,也就是说,当有新结点进来时,会在插入在链表的头部,这种方法的效率非常高,不需要遍历链表,在java1.8以后,链表元素的插入采用的数尾插法,这种方式也解决了多线程下可能引发的死锁问题。因为头插法的链表在扩容移动时,会被逆序,即后插入的先被处理,如果这个时候有另一线程进行get操作,就有可能引发死锁。

4、扩容机制不同 JDK7及其之前的java版本中HashMap的底层是链表加数组的结构,那么扩容的过程中,需要遍历链表上的每一个元素,然后按照每一个元素的hashCode值进行计算出新数组的下标。

JDK8之后的HashMap类的底层数据结构是数组和链表加红黑树,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于64,那么会优先选择数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。在JDK8中会使用到一个双向链表来维护红黑树中的元素,首先jdk8在转移某个位置上的元素时,会判断这个位置是不是一个红黑树,如果这个位置是一个红黑树,那么会遍历该位置的双向链表,遍历双向链表统计哪些元素在扩容完之后还是原位置,哪些元素在扩容之后在新位置,这样遍历完双向链表后,就会得到两个子链表,一个放在原下标位置,一个放在新下标位置,如果原下标位置或新下标位置没有元素,则红黑树不用拆分,否则判断这两个子链表的长度,如果超过八,则转成红黑树放到对应的位置,否则把单向链表放到对应的位置。

17、说⼀下HashMap的Put方法
答: HashMap类添加元素首先需要根据hash值计算数组下标,如果该位置没有元素,那就直接插入,如果定位到的数组中有元素,那就需要和该元素比较hash值和key值,如果key值相等,那就直接覆盖,如果key值不相等,那就需要判断该节点是否为树节点或者是链表节点,如果是树节点,那就直接调用树节点的插入元素的方法e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value)将元素添加进入。如果是链表节点,那就需要遍历链表节点并比较是否是相同的元素,如果实现相同的元素,那就执行值覆盖,返回旧值,如果链表中不存在相同的元素,那就把添加进的元素插入链表的尾部。注意: 使用者只能使用HashMap提供的put()方法,而不能使用putVal()方法。putVal()方法只能内部使用。

源代码解析:

// 将指定的值与此映射中的指定键相关联。如果映射先前包含键的映射,则替换旧值
public V put(K key, V value) {
		// 传入key的hash值,key值,value值
        return putVal(hash(key), key, value, false, true);
    }
 
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node[] tab; Node p; int n, i;
        // 判断table是否初始化完成,没有初始化完成则调用扩容函数
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        // (n - 1) & hash 确定元素存放在哪个桶中,桶为空,
        // 新生成结点放入桶中(此时,这个结点是放在数组中)
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
         // 如果桶中已经存在了其他的元素,不为空
        else {
            Node e; K k;
            // 分别比较hash值,key值是否相等而且不为空,如果符合,则取出这个节点
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                // 使用 e来存储 p
                e = p;
            //如果hash值不相等,也就是key不相等;则判断节点是否为树节点
            else if (p instanceof TreeNode)
            // 调用红黑树插入值的方法将元素数据存放进树节点中。
                e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
            // 上面的底层数据结构都不是,那就是链表的数据结构了。
            else {
            // 遍历到链表最后的节点
                for (int binCount = 0; ; ++binCount) {
                // 为空则是最后的节点。
                    if ((e = p.next) == null) {
                    // 在节点尾部插入数据
                        p.next = newNode(hash, key, value, null);
                         // 结点数量达到阈值(默认为 8 ),执行 treeifyBin 方法
                    	// 这个方法会根据 HashMap 数组来决定是否转换为红黑树。
                    	// 只有当数组长度大于或者等于 64 的情况下,才会执行转换红黑树操作,以减少搜索时间。否则,就是只能对数组扩容。
                        if (binCount >= TREEIFY_THRESHOLD - 1)
                            treeifyBin(tab, hash);
                        break;
                    }
                    // 判断新添加的元素是否存在于链表中,也就是判断hash值和key值是否相等且不为空。
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        // 直接跳出,因为已经存在了该值。
                        break;
                    p = e;
                }
            }
            // e!=null 说明存在旧值的key与要插入的key"相等"
            if (e != null) {
                V oldValue = e.value;
                // 进行值覆盖,然后返回旧值
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        // 如果是由于新添加的元素导致容量达到最大值,则执行扩容
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

18、对象的相等与指向他们的引用相等,两者有什么不同?
答: 对象的相等是指对象所存储的内容是否相等,引用相等是指引用所指向的地址是否相等。

19、Java中的值传递和引用传递
答: 值传递 : 方法接收的是实参值的拷贝,会创建副本。引用传递 : 方法接收的直接是实参所引用的对象在堆中的地址,不会创建副本,对形参的修改将影响到实参。在java语言中,只有值传递,没有引用传递,在java编程中,如果传入方法中的是基本的数据类型,那就会拷贝基本数据类型的变量(创建副本,值传递),如果传入方法的是引用类型,那就会拷贝引用类型的地址值(值传递)。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1037806.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号