面向对象和面向过程的区别
面向过程的编程是以过程(也称函数、方法)为中心的,强调解决问题的步骤和过程,关注每一个具体的步骤和操作,从而以此来解决问题。
面向对象的编程则是以对象为中心的,强调对问题进行抽象,通过封装、继承、多态等机制,将问题划分成一个个相对独立的对象,然后让对象之间相互协作,来解决问题。
八种基本数据类型的大小,以及他们的封装类
instance of 关键字的作用
Java自动装箱与拆箱
重载和重写的区别
重载指的是在同一个类中定义多个具有相同名称但参数列表不同的方法,用于实现不同的功能。重载的方法必须具有不同的参数列表(参数类型、参数个数或参数顺序不同),但方法的返回类型可以相同也可以不同。
重写指的是在子类中实现与父类中相同名称、相同参数列表和相同返回类型的方法,用于实现不同的行为。重写方法不能比父类中的方法访问权限更严格(即不能降低访问权限),返回类型不能比父类中的方法更严格(即返回类型可以与父类相同或是其子类),方法的参数列表必须与父类中的方法相同或是其子集。
重载和重写的主要区别在于:
- 重载是在同一个类中定义多个方法,重写是在子类中实现父类中的方法。
- 重载的方法具有相同的名称但参数列表不同,重写的方法具有相同的名称和参数列表。
- 重载的方法可以具有相同的或不同的返回类型,重写的方法必须具有相同的返回类型或其子类。
- 重载的方法是编译时多态性,重写的方法是运行时多态性。
equals与==的区别
==用于比较两个对象的引用是否相同,即判断两个对象是否为同一个对象。如果两个对象的引用相同,则它们是同一个对象;如果两个对象的引用不同,则它们不是同一个对象。
equals用于比较两个对象是否在逻辑上相等,即判断两个对象的内容是否相同。默认情况下,equals方法与==运算符作用相同,即比较两个对象的引用是否相同。但是,equals方法可以被覆盖重写,以实现比较两个对象内容是否相同的功能。
Hashcode的作用
在Java中,hashCode()是Object类中的一个方法,用于返回对象的哈希码。哈希码是一个整数,是由对象的哈希算法根据对象的状态计算出来的。它主要有两个作用:
-
在哈希表中用于快速查找:哈希表是一种以键值对形式存储数据的数据结构,它的实现依赖于哈希码。在往哈希表中添加元素时,先计算元素的哈希码,然后根据哈希码决定元素在哈希表中的位置,从而快速查找、添加、删除元素。如果两个对象的哈希码不同,那么它们在哈希表中的位置也不同,这样就可以避免哈希冲突,提高哈希表的效率。
-
用于判断对象是否相等:在Java中,如果两个对象相等,它们的哈希码一定相同;但如果两个对象的哈希码相同,并不意味着它们一定相等。因此,在判断对象是否相等时,一般需要先比较它们的哈希码,如果哈希码相同,再比较它们的实际内容,以确保判断的准确性。
为了确保哈希码的正确性,需要满足以下两个条件:
- 如果两个对象相等,它们的哈希码必须相同。
- 如果两个对象的哈希码相同,它们不一定相等。
为了满足第一个条件,需要在重写equals()方法时同时重写hashCode()方法,并确保两个方法的实现方式一致。为了满足第二个条件,可以采用一些特殊的哈希算法,例如Java中常用的“31倍加”哈希算法,可以有效降低哈希冲突的概率。
String、String StringBuffer 和 StringBuilder 的区别是什么
-
string是不可变的(immutable)类,即一旦创建了一个String对象,就不能改变它的值。每次对String进行操作,都会返回一个新的String对象。因此,在频繁修改字符串的情况下,使用String会产生大量的临时对象,导致内存消耗过多和性能降低。
-
StringBuffer和StringBuilder是可变的(mutable)类,它们都继承自AbstractStringBuilder类,提供了对字符串进行添加、删除、替换等操作的方法。StringBuilder是JDK 1.5中新增的,与StringBuffer类似,但StringBuilder没有被synchronized修饰,因此在多线程环境下性能更好。
-
StringBuffer是线程安全的类,即它的方法是同步的,因此在多线程环境下使用它可以避免数据竞争问题。但由于同步会带来额外的开销,因此在单线程环境下使用StringBuffer性能比StringBuilder差。
-
在对字符串进行频繁操作时,推荐使用StringBuilder,因为它的性能更好;在多线程环境下或需要保证线程安全时,应该使用StringBuffer;而如果只是对字符串进行少量操作,可以使用String。
ArrayList和linkedList的区别
ArrayList和LinkedList都是Java中常用的集合类,它们的主要区别在于底层数据结构和操作效率上有所不同:
-
底层数据结构:ArrayList基于动态数组实现,LinkedList基于双向链表实现。
-
插入和删除操作:由于ArrayList底层是数组,因此在插入和删除元素时需要将其它元素往后或往前移动,效率较低。而LinkedList则是通过修改前后元素的指针来实现插入和删除,效率较高。
-
访问操作:由于ArrayList是基于数组实现的,因此在通过索引进行随机访问时效率较高。而LinkedList则需要通过遍历链表来访问指定位置的元素,效率较低。
-
空间占用:由于ArrayList在创建时就需要为其分配一定的内存空间,因此在元素数量较多时,可能会浪费一定的内存空间。而LinkedList则不需要预先分配内存空间,只需要为每个元素的指针和数据分配空间,因此可以有效节省空间。
综上所述,当需要频繁进行插入和删除操作时,应该优先选择LinkedList;当需要频繁进行随机访问时,应该优先选择ArrayList。同时,由于LinkedList需要额外的指针空间来存储链表结构,因此在元素数量较多时,其空间占用也会比ArrayList更大。
HashMap和HashTable的区别
HashMap和HashTable都是Java中常用的Map实现类,它们的主要区别如下:
-
线程安全性:HashTable是线程安全的,所有方法都是同步的(synchronized),因此可以在多线程环境下使用;而HashMap则是非线程安全的,如果多个线程同时访问一个HashMap实例,可能会导致数据不一致的问题。
-
null值的处理:HashTable不允许key或value为null,否则会抛出NullPointerException异常;而HashMap允许key和value都为null。
-
性能:由于HashTable所有方法都是同步的,因此在多线程环境下可能会导致性能问题;而HashMap则不需要额外的同步操作,因此在单线程环境下性能更好。另外,HashTable中使用Enumeration进行遍历,而HashMap中使用Iterator进行遍历,由于Iterator支持删除操作,因此在需要进行遍历和删除操作时,HashMap更为方便。
综上所述,如果需要在多线程环境下使用Map,并且不允许key或value为null,应该使用HashTable;否则,可以考虑使用HashMap。需要注意的是,如果需要保证线程安全性,也可以使用ConcurrentHashMap,它是线程安全的,并且比HashTable性能更好。
Collection包结构,与Collections的区别
Collection是Java集合框架的基本接口,表示一组对象的集合,它是所有集合类的父接口。它提供了一组基本的操作方法,如添加、删除、遍历等,可以用于操作各种集合类型。
Collection接口的常见实现类包括List、Set、Queue等,它们分别代表有序的列表、无序的集合和队列。Collections则是一个工具类,提供了一系列静态方法,用于操作各种集合类的工具类。
Collections类提供了很多有用的方法,如排序、查找、替换、拷贝等,这些方法都是静态的,可以直接通过类名访问。它也提供了一些特殊的集合类型,如不可修改的集合、线程安全的集合、只读的集合等,可以通过Collections的静态方法来创建这些特殊的集合类型。
综上所述,Collection是Java集合框架的基本接口,用于表示一组对象的集合;而Collections是一个工具类,提供了一系列静态方法,用于操作各种集合类。可以说,Collection是Java集合框架的基础,而Collections则是在基础上提供了更多的实用工具方法。
Java的四种引用,强弱软虚
强引用(Strong Reference):Java中默认的引用类型就是强引用,它是指向对象的一个普通引用,只要强引用存在,垃圾回收器就不会回收该对象。
软引用(Soft Reference):软引用是一种比较弱的引用类型,在系统内存不足时,垃圾回收器会优先回收软引用类型的对象。可以使用java.lang.ref.SoftReference类来创建软引用
弱引用(Weak Reference):弱引用是一种比软引用更加弱化的引用类型,如果一个对象只被弱引用所引用,那么它在垃圾回收时会被回收掉
虚引用(Phantom Reference):虚引用是Java中最弱的一种引用类型,它与对象的生命周期没有直接关联。当一个对象被设置为虚引用时,垃圾回收器在回收该对象时会将该对象加入到一个队列中,这个队列称为引用队列(Reference Queue)。可以使用java.lang.ref.PhantomReference类来创建虚引用
Java创建对象有几种方式?



使用反序列化创建对象:Java中可以通过反序列化的方式来创建对象,即将一个对象序列化后再反序列化出来,就可以创建一个新的对象。
有没有可能两个不相等的对象有相同的hashcode
深拷贝和浅拷贝的区别是什么?
在 Java 中,对象拷贝分为浅拷贝和深拷贝两种方式:
- 浅拷贝:浅拷贝是创建一个新的对象,然后将当前对象的非静态字段复制到新对象中。如果字段是基本类型,则复制其值;如果字段是引用类型,则复制引用。这意味着新对象和当前对象共享同一个引用类型的对象。也就是说,如果更改新对象中的引用类型字段,当前对象中的相应字段也会发生更改。
- 深拷贝:深拷贝是创建一个新的对象,然后递归地将当前对象及其所有引用类型字段复制到新对象中。这意味着新对象和当前对象不共享任何引用类型的对象。也就是说,如果更改新对象中的引用类型字段,当前对象中的相应字段不会发生更改。
因此,深拷贝创建的对象和原始对象是完全独立的,而浅拷贝创建的对象和原始对象共享引用类型字段。在一些情况下,可能需要使用深拷贝来确保对象的独立性,例如在多线程环境下或在需要对对象进行修改时。
final有哪些用法?
-
修饰类:final 修饰的类不能被继承。
-
修饰方法:final 修饰的方法不能被子类重写。
-
修饰变量:final 修饰的变量在声明后不能再被赋值,被称为常量。final 变量必须在声明时初始化。
-
修饰引用变量:final 修饰的引用变量不能再指向其他对象,但是可以改变对象的状态。例如,final 修饰的引用变量指向的 ArrayList 对象可以添加或删除元素,但是不能将引用指向其他 ArrayList 对象。
-
修饰参数:final 修饰的方法参数不能在方法中被修改,也就是说,方法内部不能改变参数的值。
static都有哪些用法?
-
静态变量:使用 static 关键字修饰的变量是静态变量,也称为类变量。它们属于类,而不是属于类的实例。在一个类中,所有的实例共享同一个静态变量。静态变量可以通过类名直接访问,也可以通过对象名访问。
-
静态方法:使用 static 关键字修饰的方法是静态方法,也称为类方法。静态方法可以通过类名直接访问,也可以通过对象名访问。静态方法不能访问非静态变量和非静态方法,只能访问静态变量和静态方法。
-
静态代码块:使用 static 关键字修饰的代码块是静态代码块,也称为类初始化块。静态代码块在类被加载时执行,而且只执行一次。静态代码块常用于初始化静态变量或执行一些静态操作。
-
静态内部类:使用 static 关键字修饰的内部类是静态内部类。静态内部类可以直接访问外部类的静态变量和静态方法,但不能直接访问外部类的非静态变量和非静态方法。
Java 中 IO 流
说说List,Set,Map三者的区别?
List、Set 和 Map 是 Java 中三个常用的集合接口,它们之间的区别如下:
-
List:有序集合,允许重复元素。可以根据元素的下标访问元素,也可以通过迭代器访问元素。
-
Set:无序集合,不允许重复元素。不能通过下标访问元素,只能通过迭代器访问元素。
-
Map:键值对映射集合,每个元素包含一个键和一个值,键不能重复。可以根据键访问值,也可以通过迭代器访问键值对。
举个例子,比如有一个人名字的集合,使用 List 存储,可以按照添加顺序访问每个人的名字;使用 Set 存储,可以快速判断某个名字是否已经存在;使用 Map 存储,可以通过名字查找对应的联系方式等附加信息。
需要注意的是,Java 中的 List、Set 和 Map 接口都有不同的实现类,可以根据具体需求选择不同的实现类,例如 ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap 等。每种实现类都有自己的特点和适用场景,需要根据具体情况进行选择。
java反射的作用于原理
获取class对象的三种方式
Java 反射机制是指在运行时动态地获取类的信息以及操作类的属性、方法和构造器等内容的机制。
Java 反射的作用主要有以下几个方面:
-
动态地创建对象:通过反射可以在运行时根据类的完整名称来创建对象,而不需要提前知道类的类型。
-
动态地获取类的信息:通过反射可以在运行时获取类的名称、修饰符、父类、实现的接口、字段、方法、构造器等信息。
-
动态地操作对象:通过反射可以在运行时动态地操作对象的属性、调用对象的方法、获取和设置对象的字段等。
Java 反射的原理主要是利用了 Java 虚拟机在加载类时生成的字节码信息,通过读取字节码信息,动态地获取类的相关信息并进行操作。Java 反射主要使用了以下几个类:
-
Class 类:表示类的类对象,包含了类的各种信息,可以通过 Class.forName()、obj.getClass() 等方法获取。
-
Constructor 类:表示类的构造器,可以通过 Class.getConstructor()、Class.getDeclaredConstructor() 等方法获取。
-
Field 类:表示类的字段,可以通过 Class.getField()、Class.getDeclaredField() 等方法获取。
-
Method 类:表示类的方法,可以通过 Class.getMethod()、Class.getDeclaredMethod() 等方法获取。
通过以上类以及其它相关类和方法,可以实现对类的动态操作。需要注意的是,反射虽然强大,但是也会影响程序的性能,因此应该尽量避免过多地使用反射