Java基础

Java基础

标签(空格分隔): 面试


1. 重载和重写

  • 重载: 表示同一个类中可以有多个名称相同的方法, 但是需要参数列表不同(即参数个数和参数类型不同).
  • 重写: 表示将子类中的方法与父类中的某个方法的名称和参数完全相同,这个时候子类重写了父类的该方法, 这个是多态性的一种表现.

子类覆盖父类的时候只能抛出比父类更少的异常, 因为子类用于解决父类存在的一些问题, 所以不能比父类有更多的问题. --- 越来越完美

子类方法的访问权限只能比父类的更大,不能更小, 如果父类的该方法使用私有修饰符修饰的话, 这样就不存在继承. --- 越来越开放.


2. 抽象类和接口的区别

参数 抽象类 接口
默认的方法实现 可以有默认的方法实现 接口是抽象的,不存在方法的实现(JDK8 default).
实现 子类使用extend关键字来继承抽象类,如果子类不是抽象类的话,他需要提供抽象类中所有声明方法的实现. 子类使用关键字来implates来实现接口, 他需要提供接口中所有声明的方法和实现.
构造器 抽象类可以有构造器 接口不能有构造器
与正常的Java类的区别 除了不能实例化抽象类之外,它和普通的Java类没有区别(实例化抽象类, 其实是匿名类,需要将其中所有的抽象函数实现之后可以实现匿名类.) 接口和类不是同一个东西.
访问修饰符 抽象方法可以有public,protected,default这些访问修饰符. 接口方法默认的修饰符是public,你不可以使用其他修饰符
main方法 抽象方法可以有main方法,并且我们可以运行它 接口没有main方法,因此我们不能运行它
多继承 抽象方法可以继承一个类和实现多个接口 接口只能继承一个或者多个其他接口
速度 比接口的速度更快 接口式比较慢的,因为它需要时间去寻找在类中实现的方法
添加新方法 如果向抽象类中添加新的方法,你可以给他提供默认的实现,因此你不需要改变你现在的代码 如果在接口中添加方法,那么你必须改变实现该接口的类.
package pers.ycy.base;

public class FinalClass {
    public static void main(String[] args) {
        Animal ag = new Dog();
        new Dog();
        new Dog().run();
        Animal animal = new Animal() {
            @Override
            protected void sing() {
                System.out.println("sing");
            }
        };
        animal.sing();
    }
}

/**
 * 抽象类, 动物.
 */
abstract class Animal {
    int age;
    String name;

    public static void main(String[] args) {
        Animal sing_sing = new Animal() {
            @Override
            protected void sing() {
                System.out.println("sing sing");
            }
        };
        sing_sing.run();
    }

    // 每次创建 新对象的时候会调用一次, 运行优先级 高于构造函数 低于静态代码块.
    {
        System.out.println("构造代码块");
    }

    // 在第一次创建对象的时候会执行一次. 运行优先于 构造代码块,  通常用于初始化只调用一次的数据, 例如: 初始化程序的运行配置信息
    static {
        System.out.println("静态代码块");
    }

    Animal() {
        System.out.println("抽象类的构造函数");
    }

    abstract protected void sing();

    protected void run() {
        {
            int x = 10;
            System.out.println(x);
            System.out.println("用于限定变量的作用域.");
        }
        System.out.println("动物是可以跑得");
    }
}

class Dog extends Animal {

    @Override
    protected void sing() {
        System.out.println("汪汪");
    }
}
abstract class AGou extends Dog{

}
public class FinalClass {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
    }
}

/**
 * 接口和类 是不同的, 抽象类中的 构造代码块, 静态代码块, 构造函数. 接口中是没有的.
 */
interface Animal{
    default void eat(){
        System.out.println("接口的默认方法, 如果使用该方法, 则该方法需要对所有实现该接口的类都有用 .");
    }
}
class Dog implements Animal{
    
}

3. 说说反射的用途和实现

反射的用途
  • Java的反射机制是一个非常强大的功能, 在很多的项目当中都可以看到反射的身影Spring, Mybatis.通过反射机制我们可以在运行期间获取对象的类型信息. 利用这一点我们可以实现工厂模式和代理模式等设计模式, 同时也可以解决Java的泛型擦除问题.
反射的实现
  • 获取一个对象对应的反射类在,Java方法中有下面几种方法可以获得反射类.
  1. getClass()
  2. Class.forName()
  3. 类.class
  4. 通过类加载器实现, getClassLoader()

4. Session和Cookie的区别

  1. Cookie是存放在客户端上的,Session存放在服务器上.
  2. Cookie不是很安全, 别人可以分析存放在本地的Cookie并进行Cookie欺骗,考虑到安全应当使用Session.
  3. Session会在一定时间内保存在服务器上, 当访问增多的时候会比较占用服务器的性能, 考虑到减轻服务器的压力应当使用Cookie.
  4. 单个Cookie保存的数据不应当超过4k, 很多浏览器限定一个站点最多保存20个Cookie.

5. GET请求和POST方式的区别

  1. 根据Http规范,GET用于信息获取, 而且应该是安全的和幂等性[1]
  2. 根据HTTP规范,POST请求可以改变服务器上的资源.
  3. 首先是"GET方式提交的数据最多只能是1024字节",因为GET是通过URL提交数据,那么GET可提交的数据量就和URK长度有直接的关系了.而实际上,URL参数不存在上限,HTTP协议规范没有对URL长度进行限制,这个限制是特定的浏览器以及服务器对它的限制,IE对URL长度的限制是2083(2k+35).对于其他浏览器. 一般没有长度限制
  4. POST没有大小限制,HTTP协议规范也没有进行大小限制.

6. Session分布式处理


6.1 Session复制

在支持Session复制的Web服务器上,通过修改Web服务器的配置,可以实现将Session同步到其它Web服务器上,达到每个Web服务器上都保存一致的Session.

  1. 优点: 代码上不需要做支持和修改.
  2. 缺点: 需要依赖支持Session复制的Web服务器, 一旦更换成不支持的Web服务器就不能使用了, 并且在用户量巨大的情况下可能会造成Session大爆炸.
  3. 适用场景: 只适用于Web服务器比较少并且Session数据量比较小的情况.
  4. 可用方案: 开源方案 tomcat-redis-session-manager, 暂不支持Tomcat8.

6.2 Session 粘滞

将用户的每次请求都通过某种方法强制分发到某一个Web服务器上,只要这个Web服务器上存储了相应的Session数据,就可以实现会话跟踪.

  1. 优点: 使用简单,没有额外开销.
  2. 缺点: 一旦某个Web服务器重启或者宕机,相对应的Session数据也会丢失,而且需要依赖负载均衡机制.
  3. 适用场景: 对稳定性要求不是很高的业务情景.

6.3 Session集中管理

在单独的服务器或者服务器集群上使用缓存技术,如Redis存储Session数据,集中管理所有的Session.所有的Web服务器都从这个存储介质中去的对应的Session,实现Session共享.

  1. 优点: 可靠性高,减少Web服务器的资源开销.
  2. 缺点: 实现上有些复杂,配置较多.
  3. 适用场景: Web服务器较多,要求高可用性的情况.
  4. 可用方案: 开源方案Spring Session,也可以自己实现,主要是重写HttpServletRequestWrapper中的getSession方法.

6.4 基于Cookie管理

这种方式每次发起请求的时候都需要将Session数据放到Cookie中传递给服务端.

  1. 优点: 不需要依赖额外外部存储,不需要额外配置.
  2. 缺点: 不安全,已被带去或篡改;Cookie的长度和数量有限制,需要消耗更多的网络带宽.
  3. 使用场景:数据不重要,不敏感且数据量较小的情况.

7. JDBC的流程

  • DriverManager类注册驱动数据库驱动程序.
  • 调用DriverManager.getConnection方法,通过JDBC URL将用户名,密码,数据表等信息传入,以得到数据库链接.
  • 获取Connection之后,便可以通过createStatement创建Statement用以执行SQL语句.
  • 有时候会得到查询结果,比如select,得到查询结果,查询的结果存放于(ResultSet)当中.
  • 关闭数据库语句,关闭数据库链接.

8. MVC设计思想

MVC是三个单词的首字母缩写, 他们是Model, View, Controller. 这个模式认为, 程序不论简单与复杂, 从结构上来看,都可以分为三层:

  1. 最顶层(View): 直接面向用户的视图层. 它是提供给用户的操作界面, 是程序的外壳.
  2. 最底层(Model): 核心的用户层, 也就是程序需要操作的数据或信息.
  3. 中层(Controller): 根据用户从"视图层"输入的指令,选取"数据层"中的数据,然后对其进行相应的操作,产生最终的结果.

9. equals==的区别

两个对象用equals比较返回true,那么两个对象的hashcode方法必须返回相同的结果.

  • 问题: 如若相反的话, hashtable中, 两个自认为相同的对象(equalstrue), 在取值和存值的时候就会出现, 下表地址不同的情况. 这样就麻烦很大了.

两个对象用equals比较返回false,那么两个对象的hashcode方法也不一定返回不同的值,但是最好返回不同的值,这样可以提高哈希表的性能.

  • 两个自认为不同的对象, 在hashtable中存取值的时候下标居然相同. 这样问题就很大.

根据第二点,重写equals的时候,必须重写hashcode,以确保equals方法相等的时候两个对象的hashcode返回相同的值.

  • 由上述的两点 , equalshashcode应该保持一致性.
  • set集合去重的时候, 判断是否相等用的是 哈希值和equals同时成立与否. 这样也可以看出应该让 equalshashcode应该保持一致性.
  1. equals==的区别是: ==用于比较原生类型,而equals方法用于检查对象的相等性.
  2. 如果==equals用于比较对象,当两个引用地址相同,==返回true.而equals可以返回truefalse主要取决于重写的实现.最常见的一个例子,字符串的比较,不同情况==equals返回不同的结果.

10. listmap的区别.

Map是键值对的方式进行存储的, 根据值去获取键, List是根据下标进行存储的, 所以必须要有顺序,有下标才能顺利的进行存取. 但是Map就不需要下标,且没有顺序. 只需计算Hash值即可

Map接口有三个实现类: HashMap,HashTable,LinkedHashMap.

List接口有三个实现类: LinkList,ArrayList,Vector.

LinkedList: 底层基于链表实现, 链表内存是散乱的, 每一个内节点都存储着 上一个节点的地址和下一个节点的地址以及本身的值.

Map相当于和Collection一个级别的, Map集合存储键值对,且要求保持键的唯一性.

Map是基于哈希存储的所以要求保持键的唯一性.

其中区别: List特点 元素放入有顺序,元素且可以重复. Map特点 元素按键值对存储,无放入顺序.


11. ListSet的区别

ListSet都是继承自Collection接口.
List特点: 要么是链表要么是顺序数组,所以有顺序,元素可重复.
Set特点: HashSet(底层是HashMap),LinkedHashSet.


12. ArrayListLinkList的区别

其实就是顺序数组和链表的区别


13. ArrayListVector的区别

都是顺序数组, 但是Vector是线程安全的,ArrayList是线程不安全的.
Vector的数据增长是原来的一倍, ArrayList是增加原来的50%.

  • 堆栈,队列,这种经常存储和删除的应该使用Vector这样可以减少因为扩容产生的时间消耗.
  • 快速读取等操作应该使用ArrayList.

14. HashMapHashTable

HashMap几乎可以等价于HashTable,除了HashMap是非synchronized的,并且可以接受null(HashMap可以接受为null的键值和值,而HashTable则不可以).

HashMap是非synchronize,而HashTablesynchronize的.这意味着HashTable是线程安全的,多个线程可以共享一个HashTable,如果没有一个正确的同步的话,多个线程是不能共享HashMap的, Java5提供了ConcurrentHashMap,它是HashMap的替代,比HashMap的扩展性更好.


15. 线程安全问题

  • 最简单的方式,Synchronization关键字.
  • 使用java.util.concurrent.atomic包中的原子类, 例如AtomicInteger.
  • 使用 java.util.concurrent.locks 包中的锁
  • 使用线程安全的集合 ConcurrentHashMap
  • 使用 volatile 关键字,保证变量可见性(直接从内存读,而不是从线程 cache 读)

在JVM底层volatile 是采用“内存屏障”来实现的.
缓存一致性协议(MESI协议)它确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下:当某个 CPU 在写数据时,如果发现操作的变量是共享变量,则会通知其他 CPU 告知该变量的缓存行是无效的,因此其他 CPU 在读取该变量时,发现其无效会重新从主存中加载数据


16. synchronizedlock 的区别

  • synchronizedlock 的区别

  • synchronized(隐式锁): 在需要同步的对象中加入此控制, synchronized方法上, 也可以加在特定代码块中, 括号中表示需要上锁的对象.

  • lock(显示锁): 需要显示指定其实位置和终止位置. 一般使用ReentrantLock类作为锁, 多个线程中必须要使用一个 ReentrantLock 类做为对象才能保证锁的生效。且在加锁和解锁处需要通过 lock()unlock() 显示指出。所以一般会在 finally 块中写 unlock() 以防死锁。

  • synchronizedlock 性能区别

  • synchronized 是托管给 JVM 执行的,而 lockJava 写的控制锁的代码。在 JDK 1.5 中,synchronize 是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用 Java 提供的 Lock 对象,性能更高一些。但是到了 JDK 1.6,发生了变化。synchronize 在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在 JDK 1.6synchronize 的性能并不比 Lock 差。

17. Java跳出 一重以上循环的方式。

public static void main(String[] args) {     
    ok:                                      
    for(int i=0;i<10;i++){                   
        for(int j=0;j<10;j++){               
            if(j==5){                        
                System.out.println("j==5");  
                break ok;                    
            }                                
        }                                    
    }                                        
}                                            

18. final

final 修饰一个关键字的时候,是栈内存不能变,和堆内存无关。

public static void main(String[] args) {
    final StringBuilder a = new   StringBuilder("1qwe");
        a.append("asdasd");
}


  1. 一次请求和多个请求对于同一个资源来说应该具有同样的结果(网络超时,电脑爆炸之类的不算数.). ↩︎

posted @ 2020-04-10 15:28  X-POWER  阅读(150)  评论(0编辑  收藏  举报