JAVASE精华!全是干货!精简版复习+清晰高频面试题

1、JAVA语法基础

​ 标识符 关键字 数据类型与类型转换

  1. 标识符 :字母、数字、下划线(_)、美元符($),不能包含别的特殊符号。 不能以数字开头,标识符不能是java关键字。

  2. 关键字:有53个关键字。其中有两个保留字:const和goto

  3. 数据类型

在这里插入图片描述

Integer 在-128到127里直接在常量池 。

问题:基本类和包装类区别?

1、包装类是对象,拥有方法和字段,对象的调用都是通过引用对象的地址,基本类型不是
2.声明方式不同,基本数据类型不需要new关键字,而包装类型需要new在堆内存中进行new来分配内存空间
3.存储位置不同,基本数据类型直接将值保存在值栈中,而包装类型是把对象放在堆中,然后通过对象的引用来调用他们
4.初始值不同,int的初始值为 0 、 boolean的初始值为false 而包装类型的初始值为null
5、使用方式不同,基本数据类型直接赋值使用就好 ,而包装类型是在集合如 coolection Map时会使用

问题:char能存汉字吗? char类型占两个字节,而java默认采用Unicode码是16位,所以一个Unicode码占两个字节,java中无论汉字还是英文都是用Unicode编码来表达的,所以可以存储一个汉字。

4.ASCII码表:编码65是【A】,编码97是【a】。

5.逻辑运算符:&&是短路与,1&&2,当,1为false,2会被短路,提高程序运行效率。

6.break与count:break直接跳出当前循环的循环体,continue跳出本轮循环,继续下 一轮循环。

7.创建数组过程分析:程序创建数组 int[] a = new int[5]; 时发生了什么?

  • 在内存中开辟连续的空间,用来存放数据,长度是5

  • 给数组完成初始化过程,给每个元素赋予默认值,int类型默认值是0

  • 数组完成初始化会分配一个唯一的地址值

  • 把唯一的地址值交给引用类型的变量a去保存

    8.创建对象过程分析: Person p = new Person();

​ 9.Arrays.toString(数组)与Arrays.sort(数组)

​ Arrays.tostring: 把数组里的数据,用逗号连接成一个字符串[值1,值2]。

​ Array.sort: 对数组进行排序,对于基本类型的数组使用的是优化后的快速排序算法,效 率高 对引用类型数组,使用的是优化后的合并排序算法

​ 10、重载与重写

重载:(两同一不同)是在一个类中定义同名方法,方法名相同,如果参数个数不同一定构成重载。个数相同看参数类型,参数类型不同也构成重载。

重写:参数列表与被重写方法的参数列表必须完全相同,返回类型可以不相同,但是必须是父类返回类型的派生类。访问权限不能比父类中被重写的方法的访问权限更低。 声明为final不能被重写。 声明为static的方法不能被重写,只能说是声明。

重写的意义:在不修改源码的前提下,进行功能的修改和扩展,体现了依赖倒转原则,

面向修改关闭,面向扩展开放。

2、面向对象

面向对象是一种思想,强调的是结果,而不用去关注具体实现的过程,相对于面向过程,我们可以由原来问题的执行者变为指挥者,进而把生活中很多复杂的问题变得简单化。

面向对象三大基本特征: (如果问特征就是4个,还有个抽象。抽象主要目的是把类行为和实现细节分离开)

封装:封装是隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式,比如类和方法。 好 处:提高安全性和重用性和可维护性。

继承:继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并扩展新的能力.

多态:指同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。

多态的特点:

  • 多态的前提1:是继承
  • 前提2:要有方法的重写
  • 父类的引用指向子类的对象
  • 多态中,编译看左边,运行看右边 (编译看左就相当于看父类是不是调用子类特有的方法了,调用了就报错。运行看右是子类如果重写了父类的方法就调用子类的)

多态的出现是为了统一调用标准,向父类看齐。 父类提供的功能才能用,子类特有的功能用不了。 多态的好处:多态可以让我们不用关心某个对象具体是什么类型,就可以使用该对象的一些方法; 提高了程序的扩展性和可维护性。

在这里插入图片描述

​ 1、类和对象

类是一类事物的抽象。

有可能衍生类和对象的关系?

类是对象的模板,对象是类的一个具体实例;类是抽象的,对象是具体的。通过类来描述一类事物,用成员变量描述事物的属性,用方法描述事物的行为。
​ 2、static

是java中的一个关键字,用来修饰成员

static关键字主要有以下四种使用场景:

1、修饰成员变量和成员方法 (通过类名.xxx直接调用)
2、静态代码块
3、修饰类(只能修饰内部类)
4、静态导包(用来导入类中的静态资源,1.5之后的新特性)

​ 3、final

是java中的一个关键字,final可以修饰 类,不能被继承;修饰方法,不能被重写;修饰成员变量,就变成了常量,值不能被改变。

​ 4、静态变量和实例变量的区别

实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

​ 5、异常

异常是一些用来封装错误信息的对象。在这里插入图片描述

2.6、抽象类

概念:Java中可以定义被abstract关键字修饰的方法,这种方法只有声明,没有方法体,叫做抽象方法。Java中可以定义被abstract关键字修饰的类,被abstract关键字修饰的类叫做抽象类。

  1. 如果一个类含有抽象方法,那么它一定是抽象类
  2. 抽象类中的方法实现交给子类来完成
  3. 抽象类不能被实例化

特点

  • abstract 可以修饰方法或者类
  • 被abstarct修饰的类叫做抽象类,被abstract修饰的方法叫做抽象方法
  • 抽象类中可以没有抽象方法
  • 如果类中有抽象方法,那么该类必须定义为一个抽象类
  • 子类继承了抽象类以后,要么还是一个抽象类(就是让下一个继承呗,自己变成个抽象子类),要么就把父类的所有抽象方法都重写
  • 多用于多态中
  • 抽象类不可以被实例化

abstract注意事项

private:被私有化后,子类无法重写,与abstract相违背。

static:静态优先于对象存在,存在加载顺序问题。

final:被final修饰后,无法重写,与abstract相违背。

2.7、接口

接口不是类,没有构造方法。 接口没有成员变量,因为默认都变成了静态常量

public final static xxx

接口概念

与之前学习过的抽象类一样,接口( Interface )在Java中也是一种抽象类型,接口中的内容是抽象形成的需要实现的功能,接口更像是一种规则和一套标准.

接口特点

接口中的方法全部都是抽象方法(当然后面好像改了,可以加…)(抽象方法是省略了 public abstract )

接口和类之间可以多实现,接口与接口之间可以多继承

接口是对外暴露的规则,是一套开发规范

接口提高了程序的功能拓展,降低了耦合性

注意点

实现接口的类调用构造方法的时候会先调用父级构造方法,而接口是没构造方法。结论:如果一个类没有明确指定父类,那么默认继承顶级父类Object。

3、JAVA-API

1、String

String底层是一个封装的char[]数组,字符串不可变,被final修饰,是个常量。

3.2、【 == 和 equals() 的区别 】

== :如果比较的是基本数据变量,那么就是比较两个变量保存的数据是否相等; 如果比较的是引用数据变量:比较两个对象的地址值是否相等,即两个引用是否指向同一个对象实体。

equals() :只能适用于引用数据类型, Object类中定义的equals()和的作用都是相同的:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体; 但是,像String、Date、File、包装类都重写了Object类中的equals()的方法,重写以后,比较的是实体内容(值)是否相同。

通常情况下,我们自定义的类 如果使用equals() 的方法的话,也通常是比较两个对象的实体呢内容是否相同,那么,我们就需要Object类中的equals()方法进行重写。

3.3、【 String/StringBuilder/StringBuffer 】

为什么用 stringbuilder比 string 拼接字符串更快?

因为strin是定长的,所以拼接是返回新的对象,所以string底层拼接字符串用Stringbuilder,但是为什么还是不推荐用string拼接呢,因为是在循环里,那直接用的话每次都会创建Stringbulider,不行,那肯定是用StringBuilder拼接在循环外创建,只要创建一次。

当然如果纯粹是 String res = “hello” + “a” + “b” + “d”; 没变量,这是创建一个对象(编译器优化的,我也不知道为什么),这个不会调用StringBuilder.

Stringbuilder和StringBuffer的区别?

一个线程不安全,一个线程安全。 本质上都是在调用父类抽象类AbstractStringBuilder来干活,只不过Buffer把代码加了同步关键字,使得程序可以保证线程安全问题。

4、Integer

创建对象:

方式一: new Integer(5);
方式二: Integer.valueOf(5);
Integer类中包含256个Integer缓存对象,范围是 -128~127
使用valueOf()时,如果指定范围内的值,直接访问缓存对象不新建;如果指定范围外的值,直接新建对象。 注意:是方式二才行,方式1是行不通的,比如跟 Integer/int i = 5;比,方式一是false,方式二是true。

5、自动装箱和拆箱

自动装箱:把 基本类型 包装成对应的 包装类型 的过程
Integer a = 5;//a是引用类型,引用了包装对象的地址。
编译器会完成对象的自动装箱:Integer a = Integer.valueOf(5);

自动拆箱:从包装类型的值,自动变成 基本类型的值
int i = a;//a现在是包装类型,没法给变量赋值,需要把5取出来。
编译器会完成自动拆箱:int i = a.intValue();

6、IO流

流:方便理解,我们可以把数据的读写操作抽象成数据在"管道"中流动。

字节流:针对二进制文件
File
InputStream
FileInputStream
BufferedInputStream
ObjectInputStream
OutputStream
FileOutputStream
BufferedOutputStream
ObjectOutputStream
字符流:针对文本文件
Reader
FileReader
BufferedReader
InputStreamReader
Writer
FileWriter
BufferedWriter
OutputStreamWriter
PrintWriter一行行写出

字节输出流 不加缓冲流的话如果没关闭流的话,数据还是会存在对应文件里,因为是读了就写进去。

多去温习代码。

7、序列化与反序列化

定义

无论何种类型的数据,都是以二进制的形式在网络上传送,为了由一个进程把Java对象发送给另一个进程,需要把其转换为字节序列才能在网络上传送,把Java对象转换为字节序列的过程就称为对象的序列化,将字节序列恢复成Java对象的过程称为对象的反序列化

作用

作用就是,把对象保存起来。为了不同jvm之间共享实例对象的一种解决方案

温习代码

8、Collection ------List 、Set

arraylist 和hashmap看

csdn点击进入

============================================================================

在这里插入图片描述

Collection接口
  List 接口【数据有下标,有序,可重复】
      ArrayList子类
      LinkedList子类
      vector
  Set 接口【数据无下标,无序,不可重复】
      HashSet子类
Map 接口【键值对的方式寸数据】
  HashMap子类
  HashTable子类
  LinkedHashMap子类

arraylist内部数组默认的初始容量是10,如果不够会以1.5倍的容量增长(后续深入Arraylist)

ArrayList 与LinkedList区别简要概述

Arraylist: 底层是数组结构,查询快(可以通过下标查),增删慢,适合查询较多场景

LinkedList:底层是链表结构,查询慢,增删快,适合增删操作较多的场景。(注意:这里说的慢是指数据量大时,查中间部分慢,首位操作还是快的。

ArrayList的JDK1.8之前与之后的实现区别?

JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组
JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加第一个元素时再创建一个始容量为10的数组

9、Map

img

【 HashMap 】重点!!!!!!这些不够还要去看

1,初始化大小是16,如果事先知道数据量的大小,建议修改默认初始化大小。 减少扩容次数,提高性能 ,这是我一直会强调的点
2,最大的装载因子默认是0.75,当HashMap中元素个数达到容量的0.75时,就会扩容。 容量是原先的两倍
3,HashMap底层采用链表法来解决冲突。 但是存在一个问题,就是链表也可能会过长,影响性能
于是JDK1.8,对HashMap做了进一步的优化,引入了红黑树。
当链表长度超过8,且数组容量大于64时,链表就会转换为红黑树
当红黑树的节点数量小于6时,会将红黑树转换为链表。
因为在数据量较小的情况下,红黑树要维护自身平衡,比链表性能没有优势。

HashMap 和HashTable区别?

JDK1.8 主要区别如下:

  • 线程安全性不同。HashMap线程不安全;Hashtable 中的方法是Synchronize的。
  • key、value是否允许null。HashMap的key和value都是可以是null,key只允许一个null;Hashtable的key和value都不可为null。
  • 迭代器不同。HashMap的Iterator是fail-fast迭代器;Hashtable还使用了enumerator迭代器。
  • hash的计算方式不同。HashMap计算了hash值;Hashtable使用了key的hashCode方法。
  • 默认初始大小和扩容方式不同。HashMap默认初始大小16,容量必须是2的整数次幂,扩容时将容量变为原来的2倍;Hashtable默认初始大小11,扩容时将容量变为原来的2倍加1。
  • 父类不同。HashMap继承自AbstractMap;Hashtable继承自Dictionary。
  • 是否有contains方法。HashMap没有contains方法;Hashtable包含contains方法,类似于containsValue。

HashMap和LinkedHashmap区别?

HashMap无序,存值的时候会根据key的hashCode()来计算存储的位置(位置是散列的,所以说其无序)。

LinkedHashMap有序,就是链表+散列表(hash表)的结构,其底层采用了Linked双向链表来保存节点的访问顺序,所以保证了有序性。

============================================================================

额外话:TreeMap 默认排序规则:按照key的字典顺序来排序(升序),当然,也可以自定义排序规则:要实现Comparator接口。

10、进程与线程(看视频)

10.1进程

进程的概念:

进程就是正在运行的程序,它代表了程序所占用的内存区域。是系统进行资源分配和调度的一个独立单位。

高并发:多个进程抢占公共资源

并行:多个CPU同时处理不同的进程

10.2线程

线程是操作系统OS能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。

线程的状态点击看

notify 和notifyAll 区别

个人理解;虽然两者都是都唤醒所有等待,当前获得锁的线程不会立马释放锁,退出syxxx代码块后,去抢锁,当有线程抢到了锁,其他线程阻塞在wait状态,即使该线程释放了,没有继续唤醒那也没用。而notifyAll,是在该基础上,所有线程会继续抢,直到所有等待的都执行完毕。 简要说明:都唤醒,notify的被抢到了锁,其他的就继续wait,直到再次唤醒。而notifyAll不用,会一直抢,直到所有都执行。

同步锁

11、单例模式

饿汉式

public class 饿汉式 {
    public static void main(String[] args) {
          TestSingle single1 = TestSingle.getSingle();
          TestSingle single2 = TestSingle.getSingle();
        System.out.println(single1==single2); //true
    }
}

class TestSingle{
    private TestSingle(){};
    static private TestSingle single = new TestSingle();
    static public TestSingle getSingle(){
        return single;
    }
}

懒汉式

public class 懒汉式 {
    public static void main(String[] args) {
        MySingle single1 = MySingle.getMysingle2();
        MySingle single2 = MySingle.getMysingle2();
        System.out.println(single1==single2); //true
    }
}
class MySingle{
    private MySingle(){};
    static private MySingle single;

   static public MySingle getMysingle2(){
       if(single == null){
           single = new MySingle();
       }
       return single;
   }
}

深拷贝和浅拷贝

浅拷贝是指向被复制的内存地址,而深拷贝是创建新的内存地址用于存放复制的对象。(就像clone()和序列化)

浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制

深拷贝:对象,对象内部的引用均复制

例子:

Person p = new Person(23, "zhang");  
Person p1 = (Person) p.clone();  
String result = p.getName() == p1.getName()   
        ? "clone是浅拷贝的" : "clone是深拷贝的";  
System.out.println(result);  
打印结果为:clone是浅拷贝的。

BIO、NIO、AIO

13、反射

反射定义

反射机制是在程序运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个属性和方法。依靠此机制,可以动态的创建一个类的对象和调用对象的方法。

反射获取对象方法:

然后,有三种通过反射获取对象的方法。

Class c1 = Class.forForName("全类名");
Class c2 = 类.class;
Class c3 = 对象.getClass();

反射优缺点:

优点就是增加灵活性,可以在运行时动态获取对象实例。

缺点是反射的效率很低,而且会破坏封装,通过反射可以访问类的私有方法,不安全。

运用:

Spring 框架的 IOC 基于反射创建对象和设置依赖属性。
mybatis框架通过读取sql,得到字段名称(与属性名相同),并用反射的方式将User对象创建出来,之后调用其set方法进行参数注入。最后放到List中。

反序列化底层也是反射

设计模式:单例模式、工厂模式、代理模式等

反射的运用之动态代理

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

java动态代理实现代理步骤:

a定义被代理类:接口及接口实现类

b定义代理类,代理类构造器传入被代理类,且需要实现InvocationHandler接口的类并重写invoke方法

c生成被代理的类的实例:调用 Proxy.newProxyInstance(被代理的类.getClass().getClassLoader(),

                                                                                    被代理的类.getClass().getInterfaces(),

                                                                                     InvocationHandler的实现类);

          注意:newProxyInstance返回的是接口类型,所以java动态代理要求被代理类实现接口。

d被代理的类的实例调用需要执行的方法

JDK动态代理和CGLIB字节码生成的区别?
(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final

14、内部类

特点

  1. 内部类可以直接访问外部类中的成员,包括私有成员

  2. 外部类要访问内部类的成员,必须要建立内部类的对象

  3. 在成员位置的内部类是成员内部类

  4. 在局部位置的内部类是局部内部类

===============================================================

成员内部类被Private修饰以后,无法被外界直接创建创建对象使用,所以可以创建外部类对象,通过外部类对象间接访问内部类的资源

使用内部类的好处:隐藏,可以不想让别人轻易的访问这个类。

(匿名内部类:“其实是继承该类或者实现接口的子类匿名对象)

好处:java是不可以实现多继承的,一次只能继承一个类,我们学习接口的时候,有提到可以用接口来实现多继承的效果,即一个接口有多个实现,但是这里也是有一点弊端的,那就是,一旦实现一个接口就必须实现里面的所有方法,有时候就会出现一些累赘,但是使用内部类可以很好的解决这些问题

例子: 这是间接实现 多个继承,因为java只能单继承 。

 public class Demo1 {
      public String name() {
          return "BWH_Steven";
      }
  }
  
  public class Demo2 {
      public String email() {
          return "xxx.@163.com";
      }
  }
  
  public class MyDemo {
 
      private class test1 extends Demo1 {
          public String name() {
              return super.name();
          }
      }
  
      private class test2 extends Demo2  {
          public String email() {
              return super.email();
          }
      }
  
      public String name() {
          return new test1().name();
      }
  
      public String email() {
          return new test2().email();
      }
  
      public static void main(String args[]) {
          MyDemo md = new MyDemo();
          System.out.println("我的姓名:" + md.name());
          System.out.println("我的邮箱:" + md.email());
      }
  }

例子:针对接口的,好处显而易见,当接口里有多个方法,而你仅仅只想要实现其中一两个,但是你实例化这个大类会暴露出很多的方法,这时你用匿名内部类在里面实现后掉你想要用的方法,这样就不会暴露出那么多。

interface Inner {
      public abstract void show();
  }
  
  class Outer {
      public void method(){
          new Inner() {
              public void show() {
                  System.out.println("HelloWorld");
              }
          }.show();
      }
  }
  
  class Test {
      public static void main(String[] args)  {
          Outer o = new Outer();
          o.method();
      }
  }    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值