1-《java基础》
- 一.java基本数据类型和引用类型
- 1.基本数据类型:
- 2.引用数据类型
- 3.基本数据类型和引用数据类型区别
- 3.1 存储位置
- 3.2 传递方式
- 4.自动装箱,自动拆箱
- 二.equals和==的区别
- 三.static
- 1.static关键字的用途
- 2.static方法
- 3.static变量
- 4.static代码块
- 四.final关键字
- 五.String、StringBuffer、StringBuilder
- 六.异常处理
- 1.Java异常结构中定义有Throwable类。 Exception和Error为其子类。
- 2.Java语言异常处理
- 2.1 对代码块用try…catch进行异常捕获处理
- 2.2 在方法体外用throws进行抛出声明
- 2.3 在代码块用throw手动抛出一个异常对象
- 七、谈谈对java多态的理解?(重要)
- 1.什么是多态
- 2.多态的条件
- 3.多态的好处:
- 4.多态的实现方式:
- 八.抽象和接口(重要)
- 九.内部类
- 十.集合框架
- 1.集合和数组的区别:
- 2.常用集合的分类
- 3.list和set的区别:
- 4.Map
一.java基本数据类型和引用类型
1.基本数据类型:
整型:byte,short,int,long
浮点型:float,double
字符型:char
布尔型:boolean
其中:
- byte占一个字节
- short、char占两个字节
- int、float占四个字节
- double、long占8个字节
- boolean只有true和false
2.引用数据类型
类、 接口、 数组、 枚举、 注解
例如,String类型就是引用类型,还有Double,Byte,Long,Float,Char,Boolean,Short(注意这里和基本类型相比首字母是大写),简单来说,所有的非基本数据类型都是引用数据类型
3.基本数据类型和引用数据类型区别
3.1 存储位置
(1)基本数据类型:在方法中定义的非全局基本数据类型变量的具体内容是存储在栈中的
(2)引用数据类型:引用数据类型变量,其具体内容都是存放在堆中的,而栈中存放的是其具体内容所在内存的地址
public class Main{
public static void main(String[] args){
//基本数据类型
int i=1;
double d=1.2;
//引用数据类型
String str="helloworld";
}
}
3.2 传递方式
- 基本数据类型:在方法中定义的非全局基本数据类型变量,调用方法时作为参数是按数值传递的
- 引用数据类型:调用方法时作为参数是按引用传递的
4.自动装箱,自动拆箱
二.equals和==的区别
1.==:基本类型比较值,引用类型比较对象的地址。
2.equals:是object自带的对比方法,基本类型无法使用,只能用于对象。默认也是用的==,比较两个对象的地址值。但是equals可以重写,例如String类就已经改写了equals方法,只要字符串内容相同,就返回true。
// Object 的 equals方法
public boolean equals(Object obj) {
return (this == obj);
}
// String 的 equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
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;
3.面试题
int a =1 ;
int b =1 ;
System.out.println(a == b);
String s1 ="123";
String s2 ="123";
System.out.println(s1 == s2);
String s3 = new String("123");
System.out.println(s2 == s3);
答案是:true,true,false
解析:对于基本数据类型来说,他们是作为常量在方法区中的常量池里面以HashSet策略存储起来的,对于这样的字符串 “123” 也是相同的道理,在常量池中,一个常量只会对应一个地址,因此不管是再多的"123" 都只会存储一个地址,所以所有他们的引用都是指向的同一块地址,因此基本数据类型和String常量是可以直接通过==来直接比较的。
Integer a =127 ;
Integer b =127 ;
System.out.println(a == b);
Integer m =128 ;
Integer n =128 ;
System.out.println(a == b);
答案:true,false
解析:对于基本数据的包装类型(Byte, Short, Character, Integer, Float, Double,Long, Boolean)除了Float和Double之外,其他的六种都是实现了常量池的,因此对于这些数据类型而言,一般我们也可以直接通过==来判断是否相等。
因为Integer在常量池中的存储范围为[-128,127],127在这范围内,因此是直接存储于常量池的,而128不在这范围内,所以会在堆内存中创建一个新的对象来保存这个值,所以m,n分别指向了两个不同的对象地址,故而导致了不相等
4.equals和hashcode的关系?
默认情况下,equals相等,hashcode必相等,hashcode相等,equals不是必相等。hashcode基于内存地址计算得出,可能会相等,虽然几率微乎其微。
5.kotlin中 == 和 === 的区别
==比较内容,===比较地址
三.static
在类中,用static声明的成员变量为静态成员变量,也成为类变量。static修饰的成员方法为静态方法。静态变量的生命周期和类相同。
这里要强调一下:
普通成员变量和成员方法,从属于对象
静态成员变量和静态方法,从属于类
1.static关键字的用途
一句话描述就是:方便在没有创建对象的情况下进行调用(方法/变量)。
被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
2.static方法
由于静态方法不依赖于任何对象就可以直接访问,因此对于静态方法来说,是没有this的,因为不依附于任何对象,既然都没有对象,就谈不上this了,并且由于此特性,在**静态方法中不能访问类的非静态成员变量和非静态方法,因为非静态成员变量和非静态方法都必须依赖于具体的对象才能被调用。**反之,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法和静态成员变量。
特别说明:static方法是属于类的,非实例对象,在JVM加载类时,就已经存在内存中,不会被虚拟机GC回收掉,这样内存负荷会很大,但是非static方法会在运行完毕后被虚拟机GC掉,减轻内存压力。
3.static变量
静态变量被所有对象共享,在内存中只有一个副本,在类初次加载的时候才会初始化。
非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
4.static代码块
执行时机:静态代码块在类被加载的时候就运行了,而且只运行一次,并且优先于各种代码块以及构造函数。如果一个类中有多个静态代码块,就会按照书写的顺序执行。
静态代码块的作用:一般情况下,如果有些代码需要在项目启动的时候执行,这时就需要静态代码快,比如一个项目启动需要加载很多配置文件等资源,就可以都放在静态代码块中。
执行顺序:静态代码块>构造代码块>构造函数
四.final关键字
可以声明成员变量、方法、类以及本地变量
final 成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误
final 变量是只读的
final 申明的方法不可以被子类的方法重写
final 类通常功能是完整的,不能被继承
final 变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销
final 关键字提高了性能,JVM 和 Java 应用都会缓存 final 变量,会对方法、变量及类进行优化
方法的内部类访问方法中的局部变量,必须用 final 修饰才能访问
五.String、StringBuffer、StringBuilder
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
String 为什么要设计成不可变的?
String是不可变的(修改String时,不会在原有的内存地址修改,而是重新指向一个新对象),String用final修饰,不可继承,String本质上是个final的char[]数组,所以char[]数组的内存地址不会被修改,而且String 也没有对外暴露修改char[]数组的方法。不可变性可以保证线程安全以及字符串串常量池的实现。
六.异常处理
1.Java异常结构中定义有Throwable类。 Exception和Error为其子类。
Exception是程序本身可以处理的异常,这种异常分两大类:运行时异常和非运行时异常,程序中应当尽可能去处理这些异常。
运行时异常:都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等, 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常:是需要显示用try-catch捕捉处理的异常,如IOException等
Error是程序无法处理的错误,比如OutOfMemoryError、StackOverflowError。这些异常发生时, Java虚拟机(JVM)一般会选择线程终止。
2.Java语言异常处理
2.1 对代码块用try…catch进行异常捕获处理
finally块没有处理异常的能力。处理异常的只能是catch块。
不管有没有异常,finally 中的代码都会执行
当 try、catch 中有 return 时,finally 中的代码依然会继续执行
2.2 在方法体外用throws进行抛出声明
public void foo() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
{
//foo内部可以抛出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 类的异常,或者他们的子类的异常对象。
}
2.3 在代码块用throw手动抛出一个异常对象
public void save(User user)
{
if(user == null)
throw new IllegalArgumentException("User对象为空");
//......
}
异常处理的两个基本原则:
- 尽量不要捕获类似 Exception 这样的通用异常,而是应该捕获特定异常。
- 不要生吞异常。
七、谈谈对java多态的理解?(重要)
1.什么是多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作
2.多态的条件
1.子类继承父类并重写父类的方法。
2.父类的引用指向子类对象。
定义格式:父类类型 变量名=new 子类类型();
多态中成员的特点:
1. 多态成员变量:编译运行看左边
Fu f=new Zi();
System.out.println(f.num);//f是Fu中的值,只能取到父中的值
2. 多态成员方法:编译看左边,运行看右边
Fu f1=new Zi();
System.out.println(f1.show());//f1的门面类型是Fu,但实际类型是Zi, 所以调用的是重写后的方法。
3.多态的好处:
1.可替换性:多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。
3.接口性:多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
4.灵活性:它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性:多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
多态的例子:
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
4.多态的实现方式:
基本上是重载、接口、继承(重写) 可通过这三种方式实现多态
八.抽象和接口(重要)
抽象类的意义?
为其子类提供一个公共的类型,封装子类中的重复内容,定义抽象方法,子类虽然有不同的实现,但是定义是一致的。
接口的意义?
规范、扩展、回调。
共同点:
- 是上层的抽象层。
- 都不能被实例化。
- 都能包含抽象的方法,这些抽象的方法用于描述类具备的功能,但是不提供具体的实现。
区别:
- 在抽象类中可以写非抽象的方法,从而避免在子类中重复书写他们,这样可以提高代码的复用性,这是抽象类的优势,接口中只能有抽象的方法。
- 多继承:一个类只能继承一个直接父类,这个父类可以是具体的类也可是抽象类,但是一个类可以实现多个接口。
- 抽象类可以有默认的方法实现,接口根本不存在方法的实现。
- 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明方法的实现。子类使用关键字implements来实现接口。它需要提供接口中所有声明方法的实现。
- 构造器:抽象类可以有构造器,接口不能有构造器。
- 和普通Java类的区别:除了你不能实例化抽象类之外,抽象类和普通Java类没有任何区别,接口是完全不同的类型。
- 访问修饰符:抽象方法可以有public、protected和default修饰符,接口方法默认是public abstract**** 。你不可以使用其它修饰符。接口中的所有属性默认为:public static final ****.
- main方法:抽象方法可以有main方法并且我们可以运行它,接口没有main方法,因此我们不能运行它。
- 速度:抽象类比接口速度要快,接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
- 添加新方法:如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。
九.内部类
内部类
非静态内部类没法在外部类的静态方法中实例化。
非静态内部类的方法可以直接访问外部类的所有数据,包括私有的数据。
在静态内部类中调用外部类成员,成员也要求用 static 修饰。
创建静态内部类的对象可以直接通过外部类调用静态内部类的构造器;创建非静态的内部类的对象必须先创建外部类的对象,通过外部类的对象调用内部类的构造器。
匿名内部类
匿名内部类不能定义任何静态成员、方法
匿名内部类中的方法不能是抽象的
匿名内部类必须实现接口或抽象父类的所有抽象方法
匿名内部类不能定义构造器
匿名内部类访问的外部类成员变量或成员方法必须用 final 修饰
十.集合框架
所有的集合都在 java.util 包下,java的集合几乎是从Collection 和 map这两个接口中派生出来的,而这两个接口又有一些子类(包括子接口和实现类)
数组和链表:https://zhuanlan.zhihu.com/p/363343364
1.集合和数组的区别:
2.常用集合的分类
3.list和set的区别:
List集合
(1)ArrayList: 底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
(2)LinkedList:底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
(3)Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素
Set集合(Set 接口存储一组唯一,无序的对象。)
(1)HashSet
HashSet 是一个没有重复元素的集合。它是由HashMap实现的,不保证元素的顺序(这里所说的没有顺序是指:元素插入的顺序与输出的顺序不一致),而且HashSet允许使用null。但是只允许有一个null元素!
(2)LinkedHashSet
LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。(LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。)
(3)TreeSet
TreeSet是一个有序集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态。
Set和List的区别
(1) Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
(2)Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
(3)List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。
4.Map
Map用于保存具有映射关系的数据,Map里保存着两组数据:key和value,它们都可以使任何引用类型的数据,但key不能重复。所以通过指定的key就可以取出对应的value。
HashMap和HashTable的比较:
TreeMap: