Java 常见问题总结

Posted 王睿丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 常见问题总结相关的知识,希望对你有一定的参考价值。

喜欢记得点个赞哟,我是王睿,很高兴认识大家!

1、Java ==和equals有什么区别?

1、概念分析

基本数据类型 == 比较的是值
引用数据类型 == 比较的是内存地址

  • “==” :判断两个对象的地址是不是相等。即判断两个对象是不是同一个对象。

  • equals():判断两个对象的内容是否相等。

2、代码分析

"==" 比较基本数据类型
结果:相等

		int num1=20,num2=20;
		if(num1==num2) 
			System.out.println("相等");
		else 
			System.out.println("不相等");

"==" 比较引用数据类型
结果:不相等

		String str1="123";
		String str2 = new String("123");
		if(str1==str2) 
			System.out.println("相等");
		else 
			System.out.println("不相等");

equals() 比较引用数据类型
结果:相等

		String str1="123";
		String str2 = new String("123");
		if(str1.equals(str2)) 
			System.out.println("相等");
		else 
			System.out.println("不相等");

2、Java 的运行机制

一丶讲之前,我先给大家提个问题:

Java究竟是编译型语言还是解释型语言呢?

二丶Java 的运行机制

三丶解答提问
答案:Java是解释性语言

Java虚拟机在这里担当的是解释器的角色,他会在程序运行时编译后的 class 文件解释成计算机可识别的二进制文件数据后再执行。

3、实现线程的两种方式

方式一:继承 Thread 类
继承 Thread 类创建一个新的线程语法:

public class ThreadTest extends Thread{
	@Override			
	public void run() {
		// TODO Auto-generated method stub
		super.run();
	}
}

别怕,我们一层层分析。
当我们的自定义类继承了 Thread 类后,必须要实现run()方法。要算是一个有意义的线程
为什么这么说?
简单理解:
把线程要做的事情放到run()方法里,当线程启动后,会直接执行run()方法里面的所有代码。
好,那么问题来了。

提问:这个run()方法究竟是从哪里来的呢?
问得很好,run() 方法上方有一个@Override 标记,代表它是一个抽象方法,我们都知道子类是必须要继承父类 Thread的抽象方法的,而 Thread 又实现了Runnable 接口,接口中的方法全都是抽象方法,且不能有方法体,所以说,知道怎么来的了吧!

要想让线程能够得到执行,我们需要启动线程,这时候线程才能拿到cpu时间片从而才能启动
启动线程语法:

public static void main(String[] args){
	new ThreadTest().start();
}

例1:

public class ThreadTest extends Thread {		//继承 Thread 类
	
	private int count = 10;			
	public void run() {					//重写 run() 方法
		while(true) {
			System.out.print(count + " ");		//打印 count 变量
			if(--count == 0) {					//使 count 变量自减,当自减为 0 时,退出循环
				return;
			}
		}
	}
	
	public static void main(String[] args) {
		new ThreadTest().start();
	}

}

class A extends Thread{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
	}
}

结果为:

10 9 8 7 6 5 4 3 2 1 

重要结论:
如果不调用start() 方法,线程永远都不会启动,在主方法没有调用start()方法之前,Thread 对象只是一个实例,而不是一个真正的线程。

为什么要有第二种启动线程的方式
学习第二种方式之前,我们需要知道,为什么有1种实现了以后还要搞第二种不是浪费时间吗,不,开发者可比我们聪明多了,针对不同的情景,我们会使用不同的方式去实现。

具体原因:
如果程序员需要继承其他类(非Thread 类),因为Java不能支持多继承,此时还要使当前类实现多线程,那么就可以通过 Runnable 接口来实现。

所以我们知道了第二种方式诞生原因后,就一起来学习吧

方式二:实现 Runnable 接口
语法:

public class Thread extends Object implements Runnable

其实 Thread 类它实现了 Runnable 对象,其中的 run()方法正是对 Runnable 接口中的 run() 方法的具体实现。

实现 Runnable 接口创建线程的流程图

例1:

import java.awt.Container;
import java.net.URL;
import javax.swing.*;

public class SwingAndThread extends JFrame {
	private JLabel jl = new JLabel();		//声明 JLabel 对象
	private static Thread t;				//声明线程对象
	private int count = 0;					//声明计数变量
	private Container container = getContentPane();			//声明容器
	
	public SwingAndThread() {
		setBounds(300,200,250,100);   	//绝对定位窗体大小与位置
		container.setLayout(null);      //使窗体不适用任何布局管理器
		URL url = SwingAndThread.class.getResource("1.png");  //获取图片的URL
		Icon icon = new ImageIcon(url);		//实例化一个 Icon
		jl.setIcon(icon);    //将图标放置再标签中
		jl.setHorizontalAlignment(SwingConstants.LEFT);		//设置图片在标签的最左方
		jl.setBounds(10, 10, 200, 50);  	//设置标签的位置与大小
		jl.setOpaque(true);  	
		t = new Thread(new Runnable() {				//定义匿名内部类,该类实现 Runnable 接口
			@Override
			public void run() {						//重写run() 方法
				while(count <= 200) {				//设置循环条件
					jl.setBounds(count, 10, 200, 50);  //将标签的横坐标用变量表示
					try {
						Thread.sleep(1000);			//将线程休眠 1000 毫秒
					}catch (Exception e) {
						e.printStackTrace();
					}
					count += 30;				//使横坐标每次增加4
					if(count >= 200) {		//当图标到达标签的最右边时,使其回到标签最左边
						count=10;
					}
				}
			}
		});
		t.start();			//启动线程
		container.add(jl);	//将标签添加到容器中
		setVisible(true);  	//设置窗体可见
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);	//设置窗体关闭方式
	}
	
	public static void main(String[] args) {
		new SwingAndThread();		//实例化一个 SwingAndThread 对象
//		System.out.println(SwingAndThread.class.getResource(""));
	}

}

运行结果(有水印望各位请体谅理解):

注意:这里我要讲解下面这行代码

URL url = SwingAndThread.class.getResource("1.png");

当时我有卡在这里,因为不知道图片放在哪里,getResource() 方法才能获取到。后面百度了下,才找到了解决的方法:
可以看到,我在 main() 方法里注释了一行代码:

System.out.println(SwingAndThread.class.getResource(""));

这行代码,是用来获取当前当前项目的运行路径的。结果为:

所以能够得出,图片肯定放在bin目录下才能获取到。

总结:

  • run() 方法用来存放 线程执行逻辑
  • 只有调用 start() 方法才会产生线程实体,并且运行。

4、getResource方法

参考:原文链接

5、删除字符串最后一个字符的几种方法

参考:
java删除字符串最后一个字符的几种方法

6、字符串分割[split()]和截取[substring()]

字符串分割[split()]和截取[substring()]

7、判断一个字符串是否包含某个字符

判断一个字符串是否包含某个字符

8、String方法的总结

String方法的总结

9、List集合实现倒倒序排列

Collections.reverse(dataList);

10、JDK指定D盘安装及环境变量配置

一丶下载JDK,并将它放到我们D盘的任意一个目录下(不要放在含有中文的文件目录)

我的网盘
链接:https://pan.baidu.com/s/1qDWpLmYYknlaYrjismk0rA&shfl=sharepset
提取码:r8mq

二丶配置环境变量

%JAVA_HOME%\\bin;%JAVE_HOME%\\jre\\bin;

D:\\program\\JAVA\\jdk\\jdk1.8.0_171

.;%JAVA_HOME%\\lib;%JAVA_HOME%\\lib;\\tools.jar

%JAVA_HOME%\\bin;%JAVE_HOME%\\jre\\bin;

三丶检测是否成功
打开命令:Ctrl+R
1.输入java,显示如下内容,表示成功

2.java -version

到此,就已经完全成功了!

11、bug记录

今天来跟大家谈一下一个,我在做一个新闻项目的时候,遇到的一个很有意思的小Bug

报错的信息如下:

原因分析:

解决方法:

12、BufferReader中的readLine()方法

BufferReader:字符读取流缓冲去,在BufferReader中有一个readLine()方法,表示每次读取一行数据。

readLine()方法返回包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null,即返回的数据为回车符自己的数据,不包括回车符。

readLine()方法的原理:

readLine()方法无论读取一行数据还是读取多个字符,最终调用的方法还是读取字符流(Reader)中的read()方法,一次读取一个字符。


import java.io.FileReader;
import java.io.IOException;

/*
 * 模拟实现BufferedReader中的readLine()方法
 * */
public class MyBufferedReader {

    private FileReader fr = null;

    public MyBufferedReader(FileReader fr) {
        this.fr = fr;
    }

    public String readLine() throws IOException {
        // 定义一个临时容器,用于存放读取的数据
        StringBuilder sb = new StringBuilder();
        // 定义一个字符,用于判断是否读取到文件末尾
        int ch = 0;
        while ((ch = fr.read()) != -1) {
            if (ch == '\\r') {
                continue;
            }
            if (ch == '\\n') {
                return sb.toString();
            }else{
                sb.append((char)ch);
            }
        }

     //判断缓冲区是否还有数据,要是有数据就输出,(这种情况是避免最后一行数据没有回车符造成数据没有读出的问题)
        if(sb.length() !=0){
            return sb.toString();
        }
        return null;
    }
    
    //定义关闭方法
    public void close() throws IOException{
        if(fr != null){
            fr.close();
        }
    }
}

原文链接:https://blog.csdn.net/peituanjie/article/details/17421773

13、java.lang.NullPointerException - 如何处理空指针异常

原文:java.lang.NullPointerException - 如何处理空指针异常

14、报错:Parameter index out of range (1 > number of parameters, which is 0).

这种情况,肯定是某一个步的执行语句下表越界了,注意检查代码!
可能是解析结果集的时候,也有可能是存储值的时候

15、字符串怎么转换成整数

String s=“123”;
int i;
方法一
第一种方法:i=Integer.parseInt(s);

方法二

第二种方法:i=Integer.valueOf(s).intValue();

16、 API中文版

API中文版

17、InputStream.read(),response.getOutputStream(),OutputStream().write【IO流】

一丶 FileInputStream类:

Class FileInputStream
java.lang.Object
java.io.InputStream
java.io.FileInputStream
All Implemented Interfaces:
Closeable , AutoCloseable

public class FileInputStream
extends InputStream
A FileInputStream从文件系统中的文件获取输入字节。 什么文件可用取决于主机环境。
FileInputStream用于读取诸如图像数据的原始字节流。 要阅读字符串,请考虑使用FileReader 。

从以下版本开始:
JDK1.0
另请参见:
File , FileDescriptor , FileOutputStream , Files.newInputStream(java.nio.file.Path, java.nio.file.OpenOption…)

二丶 public FileInputStream(String name)

简介:

FileInputStream(String name)
通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

详情:

构造方法详细信息
FileInputStream
public FileInputStream(String name)
throws FileNotFoundException
通过打开与实际文件的连接创建一个FileInputStream文件,该文件由文件系统中的路径名name命名。 创建一个新的FileDescriptor对象来表示此文件连接。
首先,如果有一个安全管理器,它的checkRead方法被调用与name参数作为其参数。

如果命名文件不存在,则是一个目录而不是常规文件,或者由于某些其他原因无法打开读取,因此抛出一个FileNotFoundException 。

参数
name - 与系统相关的文件名。
异常
FileNotFoundException - 如果文件不存在,是一个目录而不是常规文件,或者由于某些其他原因无法打开阅读。
SecurityException - 如果安全管理器存在,并且其 checkRead方法拒绝对该文件的读取访问。
另请参见:
SecurityManager.checkRead(java.lang.String)

三丶 InputStream 类

org.omg.CORBA_2_3.portable
Class InputStream
java.lang.Object
java.io.InputStream
org.omg.CORBA.portable.InputStream
org.omg.CORBA_2_3.portable.InputStream
All Implemented Interfaces:
Closeable , AutoCloseable

public abstract class InputStream
extends InputStream
InputStream提供从流中读取所有映射的IDL类型。 它扩展了org.omg.CORBA.portable.InputStream。 该类定义了为CORBA 2.3添加的新方法。
从以下版本开始:
JDK1.2
另请参见:
InputStream

四丶 InputStream.read(数组)

得到数组的长度

byte[]  b = new byte[1024];
length= inputStream.read(b)

有值就会返回数组长度,没值就会返回-1

五丶 OutputStream 类

compact1, compact2, compact3
java.io
Class OutputStream
java.lang.Object
java.io.OutputStream
All Implemented Interfaces:
Closeable , Flushable , AutoCloseable
已知直接子类:
ByteArrayOutputStream , FileOutputStream , FilterOutputStream , ObjectOutputStream , OutputStream , PipedOutputStream

public abstract class OutputStream
extends Object
implements Closeable, Flushable
这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。
需要定义OutputStream子类的应用OutputStream必须至少提供一个写入一个字节输出的方法。

从以下版本开始:
JDK1.0
另请参见:
BufferedOutputStream , ByteArrayOutputStream , DataOutputStream , FilterOutputStream , InputStream , write(int)
六丶 OutputStream.write()

简介

void write(byte[] b, int off, int len)
从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。

详情

public void write(byte[] b,
int off,
int len)
throws IOException
从指定的字节数组写入len字节,从偏移off开始输出到此输出流。 write(b, off, len)的一般合同是数组b中的一些字节按顺序写入输出流; 元素b[off]是写入的第一个字节, b[off+len-1]是此操作写入的最后一个字节。
该write的方法OutputStream调用写出在每个字节中的一个参数的写入方法。 鼓励子类覆盖此方法并提供更有效的实现。

如果b是null ,则抛出NullPointerException 。

如果off为负数,或len为负数,或off+len大于数组b的长度,则抛出IndexOutOfBoundsException 。

参数
b - 数据。
off - 数据中的起始偏移量。
len - 要写入的字节数。
异常
IOException - 如果发生I / O错误。 特别地,如果输出流关闭,则抛出IOException 。

七丶 OutputStream.close()

简介

close()
关闭此输出流并释放与此流相关联的任何系统资源。

详情

public void close()
throws IOException
关闭此输出流并释放与此流相关联的任何系统资源。 close的一般合同是关闭输出流。 封闭流不能执行输出操作,无法重新打开。
该close的方法OutputStream什么都不做。

Specified by:
close在界面 Closeable
Specified by:
close在界面 AutoCloseable
异常
IOException - 如果发生I / O错误。

八丶 InputStream.close()
同上

九丶 代码解析

//要下载哪一个文件,获取文件名
		String  fileName = request.getParameter("fileName");
		fileName = new String(fileName.getBytes("iso-8859-1"), "utf-8");
		System.out.println("fileName:"+fileName);
		
		//找到要下载的这个文件路径 如果项目部署在安装的Tomcat下
		//F:\\\\online\\\\servlet\\\\teach\\\\day01\\\\soft\\\\apache-tomcat-7.0.52\\\\webapps\\\\Servlet06\\\\upload
		String   path = getServletContext().getRealPath("/upload");
		System.out.println("path:"+path);
		
		System.out.println("File.separator:"+File.separator);
		
		
		//文件名需要根据不同的浏览器进行转码,否则如果下载的文件,文件名是中文的话,就好出问题
		//attachment:通知浏览器以下载的形势打开这个页面
		response.setHeader("Content-Disposition", "attachment;fileName="+getStr(request,fileName));
		
		//输入流 
		InputStream  inputStream = new FileInputStream(path+File.separator+fileName);
		
		//响应输出流
		OutputStream  outputStream = response.getOutputStream();
		
		int length = 0;
		//桶
		byte[]  b = new byte[1024];
		
		while ((length= inputStream.read(b)) != -1) {
			outputStream.write(b, 0, length);
		}
		outputStream.close();
		inputStream.close();
	}

18、Map.keySet()、Map.put()、Map.get()【Map类、Set类】

首先,不要慌,大家来看一下API的介绍,最后会用一个代码例子进行解析:

一丶 Map<K,V>

Interface Map<K,V>
参数类型
K - 由此地图维护的键的类型
V - 映射值的类型
All Known Subinterfaces:
Bindings , ConcurrentMap <K,V>, ConcurrentNavigableMap <K,V>, LogicalMessageContext , MessageContext , NavigableMap <K,V>, SOAPMessageContext , SortedMap <K,V>
所有已知实现类:

AbstractMap , Attributes , AuthProvider , ConcurrentHashMap , ConcurrentSkipListMap , EnumMap , HashMap , Hashtable , IdentityHashMap , LinkedHashMap , PrinterStateReasons , Properties , Provider , RenderingHints , SimpleBindings , TabularDataSupport , TreeMap , UIDefaults , WeakHashMap



public interface Map<K,V>
将键映射到值的对象。 地图不能包含重复的键; 每个键可以映射到最多一个值。
这个接口取代了Dictionary类,它是一个完全抽象的类而不是接口。

Map界面提供了三个集合视图 ,允许将映射内容视为一组键,值集合或键值映射集合。 地图的顺序被定义为其中在地图上的集合视图迭代返回元素的顺序。 一些地图实现,如TreeMap课程,对他们的订单做出了具体的保证; 其他人,像HashMap班,不要。

注意:如果使用可变对象作为地图键,必须非常小心。 如果对象的值以影响equals比较的方式更改,而对象是地图中的键,则不会指定地图的行为。 这个禁令的一个特殊情况是,地图不允许将自己包含在内。 虽然地图可以将其本身作为一个值,但建议您非常小心: equals和hashCode方法在这样的地图上已经不太明确。

所有通用映射实现类应提供两个“标准”构造函数:一个创建空映射的void(无参数)构造函数,以及一个具有类型为Map的单个参数的构造函数 ,它创建一个具有相同键值的新映射映射作为参数。 实际上,后一个构造函数允许用户复制任何地图,产生所需类的等效地图。 没有办法强制执行此建议(因为接口不能包含构造函数),而JDK中的所有通用映射实现都符合要求。

包含在该界面中的“破坏性”的方法,即,修改其操作地图的方法,被指定抛出UnsupportedOperationException如果此映射不支持该操作。 如果是这种情况,如果调用对地图没有影响,这些方法可能会但不是必须抛出UnsupportedOperationException 。 例如,如果映射映射为“叠加”的地图为空,则可以在不可修改的映射上调用putAll(Map)方法,但不是必须抛出异常。

一些地图实现对它们可能包含的键和值有限制。 例如,一些实现禁止空键和值,有些对键的类型有限制。 尝试插入不合格的键或值会抛出未经检查的异常,通常为NullPointerException或ClassCastException 。 尝试查询不合格键或值的存在可能会引发异常,或者可能只是返回false; 一些实现将展现出前者的行为,一些实现将展现出后者。 更一般来说,尝试对不符合条件的密钥或值的操作,其完成不会导致将不合格元素插入到地图中可能会导致异常或可能成功执行该选项。 此异常在此接口的规范中标记为“可选”。

Collections Framework接口中的许多方法都是按照equals方法定义的。 例如,对于在本说明书containsKey(Object key)方法表示:“返回true当且仅当此映射包含一个键k使得(keynull ? knull : key.equals(k))的映射。” 该规范不应该被解释为意味着具有非空参数调用key Map.containsKey会导致key.equals(k)被调用的任意键k。 实现可以实现优化,从而避免equals的调用,例如,首先比较两个密钥的哈希码。 ( Object.hashCode()规范保证具有不等的哈希码的两个对象不能相等。)更一般地,各种Collections Framework接口的实现可以随意使用底层Object方法的指定行为,无论执行者认为适当。

执行递归遍历地图的一些地图操作可能会失败,并且地图直接或间接包含自身的自引用实例有异常。 这包括clone() , equals() , hashCode()和toString()方法。 实现可以可选地处理自引用场景,然而大多数当前实现不这样做。

此接口是成员Java Collections Framework 。

从以下版本开始:
1.2
另请参见:
Collection , List

以上是关于Java 常见问题总结的主要内容,如果未能解决你的问题,请参考以下文章

经验总结:Java高级工程师面试题-字节跳动,成功跳槽阿里!

BootStrap有用代码片段(持续总结)

BootStrap实用代码片段(持续总结)

python常用代码片段总结

Java习惯用法总结

Java 8 新特性总结