interview

前端

后端

Java

有基本数据类型,为什么还需要包装类型?
1、Java中提供了8种基本的数据类型,分别是byte、short、int、long、float、double、char、boolean。每一个基本的数据类型都会对应一个包装类型。
2、装箱:把基本数据类型转换为对应的包装类型。
      Integer integer = new Integer(1); //手动装箱
      Integer integer1 = Integer.valueOf(1); //手动装箱
      Integer integer = 1; 自动装箱;jdk1.5增加的功能;在编译时会调用Integer.valueOf(int i)来装箱。
3、拆箱:把包装类型转换为对应的基本数据类型。

package com.cy.test;  

public class TestJack {  
 
   public static void main(String[] args) {  
         
       @SuppressWarnings("deprecation")  
       Integer integer = new Integer(5);           
       System.out.println(integer); //print:5 
         
       int i = integer.intValue(); //手动拆箱  
       System.out.println(i); //print:5  
         
      int j = integer; //自动拆箱  
      System.out.println(j); //print:5  
 
   } 
    
}  

      自动拆箱实际上会在编译期调用intValue().
4、Java是一个面向对象的语言,而基本数据类型不具备面向对象的特性。

什么是Java?
Java是一门面向对象的高级编程语言,不仅吸收了C++语言的各种优点,比如继承了C++语言面向对象的技术核心。还摒弃了C++里难以理解的多继承、指针等概念,同时也增加了垃圾回收机制,释放掉不被使用的内存空间,解决了管理内存空间的烦恼。因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。

Java的跨平台原理。
由于各操作系统(Windows、Linux等)支持的指令集不完全一致,程序在不同的操作系统上要执行不同的程序代码。Java开发了适用于不同操作系统及位数的Java虚拟机来屏蔽各系统之间的差异,提供统一的接口。因此只需要在不同的操作系统上安装对应的Java虚拟机,Java程序只要遵循Java规范,就可以在所有的操作系统上运行Java程序了。
Java通过不同的系统、不同版本、不同位数的Java虚拟机(JVM)来屏蔽不同的系统指令集差异而对外提供统一的接口(Java API)。程序只需要按照接口开发即可。如果系统需要部署到不同的环境时,只需要在系统上安装对应版本的Java虚拟机即可。

面向对象的特征。
封装、继承、多态、抽象。

  • 封装:将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。
  • 继承:在定义和实现一个类的时候,可以在一个已经存在的类的基础上来进行。把这个已经存在的类所定义的内容作为自己的内容,并且可以添加若干新的内容,或修改原来的方法使之更适合特殊的需要。
  • 多态:程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才能确定,即一个引用变量指向哪个类的实例对象、该引用变量发出的方法调用是哪个类实现的方法,必须在程序运行期间才能确定。
    父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。
    程序调用的方法在运行期才动态绑定。
    引用变量所指向的具体实例对象的方法是内存中正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
  • 抽象:找出一些事物的相似和共性,将这些事物归为一个类,该类只考虑这些事物的相似和共性之处,并且忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。抽象就是把现实生活中的对象抽象为类。

JDK和JRE有什么区别?

  • JDK:Java Development Kit的简称,Java 开发工具包,提供了Java的开发环境和运行环境。
    JRE:Java Runtime Environment的简称,Java运行环境,为Java的运行提供了所需环境。
  • JDK其实包含了JRE,同时还包含了编译Java源码的编译器javac,还包含了很多Java程序调试和分析的工具。
  • 如果需要运行Java 程序,只需安装JRE就可以了,如果需要编写Java程序,需要安装JDK。
    在这里插入图片描述

Java中的集合。
1、Java中的集合分为value和key:value(Conllection、Map)两种。
2、存储值又分为:List和Set。
      List:有序可以重复。
      Set:无序不可重复。根据equals和hashcode判断,如果一个对象要存储在Set集合中,必须重写equals()和hashCode()。

实现一个拷贝文件的工具类是使用字节流还是字符流?
1、如果文件是文本文件,可以使用字符流。
2、如果文件包含图片、音频、图像等,则必须使用字节流
3、为了通用性,拷贝文件使用字节流。

线程的实现方式?线程怎么启动?
1、通过继承Thread类实现一个线程,Java只支持单继承,所以此种方法扩展性不强。
      Thread thread = new Thread(继承了Thread类的对象\实现了Runnable接口的对象);
      thread.setName(“”); //在创建线程后,都要设置名称。
      thread.start(); //启动
      执行的是重写的Thread类中的run方法。

2、通过实现Runnable接口实现一个线程。
      怎么区分线程?在一个系统中有很多线程,每个线程都会打印日志,想区分是哪个线程打印的怎么办?
      在创建线程的时候:thread.setName(“”);

	package com.cy.test;  
	
	public class TestJack {  
	  
	    public static void main(String[] args) {  
	        Thread thread = new Thread(new MyThread());  
	        thread.setName("jack");  
	        thread.start();  
	          
	    }  
	}  
	  
	class MyThread extends Thread{  
	    @Override  
	    public void run() {  
	        System.out.println("hi");  
	    }  
	}  

线程池、线程并发、线程池的作用?
Executors提供了四个静态方法创建线程池,分别为
1、newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2、newFixedThreadPool 创建一个定长线程池,可控制线程的最大并发数,超出的线程会在队列中等待。
3、newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4、newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO、LIFO、优先级)执行。

线程池的作用:
1、限定线程的个数,避免由于线程过多而导致系统运行缓慢或崩溃。
2、线程池不需要每次都去创建或销毁,节约了资源。
3、线程池不需要每次都去创建,响应时间更快。

以下输出结果是什么?

package stream;

public class Jack {
	
	public static void main(String[] args) {
		
		int i = 1;
		i = i++; 
		
		System.out.println(i); 
		
		int j = i++; 
		
		int k = i + ++i * i++; 
		        
		System.out.println(i); //print:4
		System.out.println(j); //print:1
		System.out.println(k); //print:11
		
	}
	
}

Spring

Spring MVC

MyBatis

MyBatis中#{}和${}的区别是什么?

1、#{}是预编译处理,是占位符;${}是字符串替换,是拼接符。
2、MyBatis在处理#{}时,会将sql中的#{}替换为?,调用PreparedStatement来赋值。
      MyBatis在处理${}时,会把${}替换成变量的值,调用Statement来赋值。
3、#{}的变量替换是在DBMS中,变量替换后,#{}对应的变量自动加上单引号。
      ${}的变量替换是在DBMS外,变量替换后,${}对应的变量不会加上单引号。
4、使用#{}可以有效防止SQL注入,提高系统的安全性。

数据库

MySQL

Oracle

Redis

设计模式

什么是设计模式?常用的设计模式有哪些?

设计模式是经过前人无数次的实践总结出来的,设计过程中可以反复使用的、可以解决特定问题的设计方法。

1、单例模式(饿汉式、懒汉式):
(1)构造方法私有化,除了可以在自己类中创建,其他地方都不能创建。
(2)自己在自己的类中创建一个单实例(饿汉式是一出来就创建单实例,而饥、懒汉式需要的时候才创建)
(3)提供一个方法获取该实例对象.

  • 饿汉式(静态常量)
    code
package com.atguigu.singleton.type1;

//单例模式:饿汉式(静态常量)
public class SingletonTest01 {

	public static void main(String[] args) {
		
		Singleton instance = Singleton.getInstance();
		System.out.println(instance);
		System.out.println("instance hashCode=" + instance.hashCode());
		
		Singleton instance1 = Singleton.getInstance();
		System.out.println(instance1);
		System.out.println("instance1 hashCode=" + instance1.hashCode());
		
		System.out.println(instance == instance1); //print:true
			
	}

}


class Singleton {
	
	//1、构造器私有化, 外部不能new
	private Singleton() {}
	
	//2、本类内部创建对象实例
	private final static Singleton INSTANCE = new Singleton();
	
	//3、提供一个公有的静态方法,返回实例对象
	public static Singleton getInstance() {
		return INSTANCE;
	}
	
}

优点:在类装载的时候就完成了实例化,避免了线程同步问题。
缺点:由于在类装载的时候就完成了实例化,因此没有达到lazy loading的效果。如果从始至终都未使用过这个实例,则会造成内存浪费。

结论:这种单例模式可用,但有可能会造成内存浪费。

  • 饿汉式(静态代码块):
package com.atguigu.singleton.type2;

//单例模式:饿汉式(静态代码块)
public class SingletonTest02 {

	public static void main(String[] args) {
		
		Singleton instance = Singleton.getInstance();
		System.out.println(instance);
		System.out.println("instance hashCode=" + instance.hashCode());
		
		Singleton instance1 = Singleton.getInstance();
		System.out.println(instance1);
		System.out.println("instance1 hashCode=" + instance1.hashCode());
		
		System.out.println(instance == instance1); //print:true
		
	}

}

class Singleton {
	
	//1、构造器私有化, 外部不能new
	private Singleton() {}
	
	//2、本类内部创建对象实例
	private final static Singleton INSTANCE;
	
	static { //在静态代码块中,创建单例对象
		INSTANCE = new Singleton();
	}
	
	//3、提供一个公有的静态方法,返回实例对象
	public static Singleton getInstance() {
		return INSTANCE;
	}
	
}

这种方式和单例模式:饿汉式(静态代码块)方式一样,只不过将类实例化的过程放在了静态代码块中,也是类装载的时候就初始化类的实例。
结论:这种单例模式可用,但有可能会造成内存浪费。

  • 饿汉式(枚举)
package com.atguigu.singleton.type8;

//单例模式:饿汉式(枚举)
public class SingletonTest08 {
	
	public static void main(String[] args) {
		
		Singleton instance = Singleton.INSTANCE;
		Singleton instance1 = Singleton.INSTANCE;
		
		System.out.println(instance);
		System.out.println(instance1);
		System.out.println(instance.hashCode());
		System.out.println(instance1.hashCode());
		System.out.println(instance == instance1); //print:true
			
		instance.sayOk();
		instance1.sayOk();
		
	}
	
}

//使用枚举,可以实现单例模式的饿汉式
enum Singleton {
	
	INSTANCE; //属性
	
	public void sayOk() {
		
		System.out.println("ok");
		
	}
	
}

说明:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

  • 懒汉式(线程不安全)
    code
package com.atguigu.singleton.type3;

//单例模式之懒汉式;线程不安全
public class SingletonTest03 {

	public static void main(String[] args) {
		
		Singleton singleton = Singleton.getInstance();
		Singleton singleton1 = Singleton.getInstance();
		
		System.out.println(singleton);
		System.out.println(singleton.hashCode());
		
		System.out.println(singleton1);
		System.out.println(singleton1.hashCode());
		
		System.out.println(singleton == singleton1);
		
	}

}

class Singleton {
	
	private Singleton() {}
	
	private static Singleton instance;
	
	//提供一个静态的公有方法,当使用到该方法时,才去创建instance
	public static Singleton getInstance() {
		
		if(instance == null) { //没有创建过实例才去创建
			
			instance = new Singleton();
			
		}
		
		return instance;
		
	}
	
}

说明:
1、起到了lazy loading 的效果,但是只能在单线程下使用。
2、如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

演示线程不安全
code

package stream;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Jack {
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		Callable<Singleton> callable = new Callable<Singleton>() {

			@Override
			public Singleton call() throws Exception {
				
				return Singleton.getInstance();
			}
			
		};
		
		ExecutorService executorService = Executors.newFixedThreadPool(2);
		
		Future<Singleton> future = executorService.submit(callable);
		Future<Singleton> future1 = executorService.submit(callable);
		
		Singleton singleton = future.get();
		Singleton singleton1 = future1.get();
		
		System.out.println(singleton == singleton1);
		System.out.println(singleton);
		System.out.println(singleton1);
		
	}
	
}

class Singleton {
	
	private Singleton() {}
	
	private static Singleton instance;
	
	//提供一个静态的公有方法,当使用到该方法时,才去创建instance
	public static Singleton getInstance() {
		
		if(instance == null) { //没有创建过实例才去创建
			
			try {
				Thread.sleep(100); //为了演示线程不安全,休眠100毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			instance = new Singleton();
			
		}
		
		return instance;
		
	}
	
}
  • 懒汉式(同步方法):线程安全
    code
package com.atguigu.jack;

public class TestJack {

	public static void main(String[] args) {
		
		Singleton singleton = Singleton.getInstance();
		Singleton singleton1 = Singleton.getInstance();
		
		System.out.println(singleton);
		System.out.println(singleton.hashCode());
		
		System.out.println(singleton1);
		System.out.println(singleton1.hashCode());
		
		System.out.println(singleton == singleton1);
		
	}

}

class Singleton {
	
	private Singleton() {}
	
	private static Singleton instance;
	
	public static Singleton getInstance() {
		
		if(instance == null) {
			
			synchronized(Singleton.class) { 
				
				instance = new Singleton();
				
			}
		}
		
		return instance;
		
	}
	
} 

说明:效率低,每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。

  • 懒汉式(同步代码块):线程安全
    code
package com.atguigu.jack;

public class TestJack {

	public static void main(String[] args) {
		
		Singleton singleton = Singleton.getInstance();
		Singleton singleton1 = Singleton.getInstance();
		
		System.out.println(singleton);
		System.out.println(singleton.hashCode());
		
		System.out.println(singleton1);
		System.out.println(singleton1.hashCode());
		
		System.out.println(singleton == singleton1);
		
	}

}

class Singleton {
	
	private Singleton() {}
	
	private static Singleton instance;
	
	public static Singleton getInstance() {
		
		if(instance == null) {
			
			synchronized(Singleton.class) { 
				
				instance = new Singleton();
				
			}
		}
		
		return instance;
		
	}
	
} 

说明:假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。

  • 懒汉式(双重检查):线程安全
    code
package com.atguigu.singleton.type6;

//单例模式之懒汉式;线程安全;加入双重检查机制
public class SingletonTest06 {

	public static void main(String[] args) {
		
		Singleton singleton = Singleton.getInstance();
		Singleton singleton1 = Singleton.getInstance();
		
		System.out.println(singleton);
		System.out.println(singleton.hashCode());
		
		System.out.println(singleton1);
		System.out.println(singleton1.hashCode());
		
		System.out.println(singleton == singleton1);
		
	}

}

class Singleton {
	
	private Singleton() {}
	
	private static volatile Singleton instance;

	//提供一个静态的公有方法,加入双重检查机制,解决线程安全问题, 同时解决懒加载问题,保证了效率
	public static synchronized Singleton getInstance() {
		
		if(instance == null) {
			
			synchronized (Singleton.class) {
				
				if(instance == null) {
					
					instance = new Singleton();
					
				}
				
			}
			
		}
		
		return instance;
		
	}
	
}

说明:
1、double check概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if (singleton == null)检查,这样就可以保证线程安全了。
2、实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象,也避免的反复进行方法同步。
3、线程安全;延迟加载;效率较高。

在实际开发中,推荐使用这种单例设计模式。

  • 懒汉式(静态内部类):线程安全
    code
package com.atguigu.singleton.type7;

//单例模式之懒汉式:静态内部类
public class SingletonTest07 {

	public static void main(String[] args) {
		
		Singleton singleton = Singleton.getInstance();
		Singleton singleton1 = Singleton.getInstance();
		
		System.out.println(singleton);
		System.out.println(singleton.hashCode());
		
		System.out.println(singleton1);
		System.out.println(singleton1.hashCode());
		
		System.out.println(singleton == singleton1);
		
	}

}

class Singleton {
	
	//构造器私有化
	private Singleton() {}
	
	//写一个静态内部类,该类中有一个静态属性:Singleton
	private static class SingletonInstance { //JVM装载内部类的时候是线程安全的
		
		private static final Singleton INSTANCE = new Singleton(); 
		
	}
	
	//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
	public static synchronized Singleton getInstance() {
		
		return SingletonInstance.INSTANCE;
		
	}
	
}

说明:
1、这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
2、静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。
3、类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
4、优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率比较高。

静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的。
因为是在内部类加载和初始化时创建的,因此是线程安全的。

额外代码:

1.	package com.cy.test;  
2.	  
3.	public class Person {  
4.	    //构造方法私有化  
5.	    private Person() {}  
6.	      
7.	    private static Person person = null ;  
8.	      
9.	    //提供方法获取  
10.	    public synchronized static Person getPerson() {  
11.	          
12.	        if(person==null) {  
13.	            person = new Person();  
14.	        }  
15.	          
16.	        return person;  
17.	    }  
18.	      
19.	    public static void main(String[] args) {  
20.	        Person.getPerson().toString();  
21.	    }  
22.	}  

2、工厂模式:SpringIOC使用了工厂模式
对象的创建交给一个工厂去创建。
3、代理模式
4、包装模式

数据结构与算法

Spring、SpringMVC

MyBatis

Zookeeper

Dubbo

RabbitMQ

Kafka

Mycat

Mycat关键特性

答案见官网

什么是Mycat

答案见官网

Mycat监控

答案见官网

Mycat的优势

答案见官网

Java Web

get和post的区别

  • get和post请求都是http的请求方式,用户通过不同的http的请求方式完成对资源(url)的不同操作。
    get、post、put、delete对应着对资源的查、改、增、删4个操作。get一般用于获取、查询资源信息,而post一般用于更新资源信息。
  • http定义了与服务器交互的不同方法,最基本的方法有4种,分别是get、post、put、delete。
    url全称是资源描述符。一个url地址用于描述一个网络上的资源,而http中的get、post、put、delete就对应着对这个资源的查、改、增、删4个操作。

1、get请求提交的数据会在地址栏中显示,而post请求提交的数据不会在地址栏中显示。
get请求提交的数据会附在url之后(把数据放置在htpp协议头中),以?分隔url和传输数据。多个参数用&连接。post提交是把提交的数据放置在http包的包体中。因此,get提交的数据会在地址栏中显示,而post提交地址栏不会改变。
2、传输的数据大小
http get请求由于浏览器对地址长度的限制而导致传输的数据有限制,而post请求不会因为地址长度限制而导致传输数据的限制。
3、安全性
post提交方式的安全性要比get提交的安全性高。由于post提交方式数据是会在地址中显示,所以可以通过历史记录找到密码等关键信息。

Servlet是什么?

Servlet(Server Applet),全称Java Servlet,是用Java编写的服务器端程序,而这些Sevlet都要实现Servlet接口,其主要功能在于交互式地浏览和修改数据,生成动态的Web内容。Servlet运行在支持Java的应用服务器中。
HttpServlet可以重写doGet()和doPost()或者也可以重写service()完成对get和post请求的响应。

Servlet的生命周期

Servlet有良好的生存期定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init()、service()和destroy()表示。
Servlet启动时,开始加载Servlet,生命周期开始。Servlet被服务器实例化后,容器运行其init(),请求到达时运行service(),service方法自动派遣运行与请求对应的doXXX方法(doGet、doPost)等,当服务器决定将实例销毁的时候(服务器关闭)调用其destroy()。
加载Servlet的class->实例化Servlet->调用Servlet的init完成初始化->响应请求(Servlet的service方法)->Servlet容器关闭(Servlet的destory方法)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值