JDK包含JRE包含JVM
continue:指跳出当前的这一次循环,继续下一次循环。
break:指跳出整个循环体,继续执行循环下面的语句。
return 用于跳出所在方法,结束该方法的运行。
Java 中有 8 种基本数据类型,分别为:
-
6 种数字类型:
- 4 种整数型:
byte、short、int、long - 2 种浮点型:
float、double
- 4 种整数型:
-
1 种字符类型:
char -
1 种布尔型:
boolean。
方法
-
类包含方法。构造方法、静态方法、实例方法
-
被static修饰的方法,叫静态方法。
- 是属于类的,不用创建对象,就可通过
类名.方法名访问。(也可用对象.方法名调用,少)
- 是属于类的,不用创建对象,就可通过
-
没被static修饰的方法,叫实例方法
- 属于实例的。需要先new对象才能用
对象.方法名调用
- 属于实例的。需要先new对象才能用
-
构造方法
- 创建对象时自动执行,无需调用
- 名字与类名相同
- 没有返回值,但不能用void声明
- 默认提供无参构造
- 可有多个构造方法,通过方法重载实现
变量
- 类的变量:成员变量——可被public、private、static、final修饰
- 被static修饰的成员变量,也叫静态变量,属于类的,被所有实例共享(创建多个对象只分配一次内存)。存储在堆中
- 静态变量被final修饰,变成常量
- 没被static修饰的成员变量,属于实例。需要new对象才能用
对象.调用
- 被static修饰的成员变量,也叫静态变量,属于类的,被所有实例共享(创建多个对象只分配一次内存)。存储在堆中
- 方法的变量:局部变量——可被final修饰
- 存储在栈中
成员变量与局部变量的区别?
成员变量 vs 局部变量
- 语法形式:从语法形式上看,成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可以被
public,private,static等修饰符所修饰,而局部变量不能被访问控制修饰符及static所修饰;但是,成员变量和局部变量都能被final所修饰。 - 存储方式:从变量在内存中的存储方式来看,如果成员变量是使用
static修饰的,那么这个成员变量是属于类的,如果没有使用static修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。 - 生存时间:从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。
- 默认值:从变量是否有默认值来看,成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(一种情况例外:被
final修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。
静态变量有什么作用?
静态变量也就是被 static 关键字修饰的变量。它可以被类的所有实例共享,无论一个类创建了多少个对象,它们都共享同一份静态变量。也就是说,静态变量只会被分配一次内存,即使创建多个对象,这样可以节省内存。
静态变量是通过类名来访问的,例如StaticVariableExample.staticVar(如果被 private关键字修饰就无法这样访问了)。
重载和重写有什么区别?
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法
# 重载
发生在同一个类中(或者父类和子类之间),方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。
综上:重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。
# 重写
重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写。
- 方法名、参数列表必须相同,子类方法返回值类型应比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。
- 如果父类方法访问修饰符为
private/final/static则子类就不能重写该方法,但是被static修饰的方法能够被再次声明。 - 构造方法无法被重写
# 总结
综上:重写就是子类对父类方法的重新改造,外部样子不能改变,内部逻辑可以改变。
面向对象和面向过程的区别
两者的主要区别在于解决问题的方式不同:
- 面向过程把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题。
- 面向对象会先抽象出对象,然后用对象执行方法的方式解决问题。
另外,面向对象开发的程序一般更易维护、易复用、易扩展。
对象的相等和引用相等的区别
==和equals的区别
- 对象的相等一般比较的是内存中存放的内容是否相等。A.equals(B)
- 引用相等一般比较的是他们指向的内存地址是否相等。A==B
面向对象三大特征
封装
- 把对象属性隐藏在内部,不允许外部直接访问。
- 提供可被外界访问的方法来操作属性。getxx,setxx方法
继承
- 子类继承父类所有的属性和方法(包括私有属性和私有方法),还能添加自己独有的属性和方法。增强代码复用性
- 子类继承的父类中的私有属性和方法,子类是无法访问,只是拥有。
- 子类可以用自己的方式实现父类的方法。(以后介绍)。
多态
- ⭐多种形态。不同子类对象调用父类的同一个方法,产生不同的结果。
- ⭐多种状态。编译和运行时的不同状态。
- 需要继承/实现关系
- 需要有方法重写
- 具体表现为父类的引用指向子类的对象。(向上转型)
注:
- 编译时,编译器去父类中找方法,找到了,编译通过。叫静态绑定。
- 运行时,寻找引用指向的堆中实际的子类对象,调用子类对象重写后的方法,叫动态绑定。
接口和抽象类有什么共同点和区别?
共同点:
- 都不能被实例化。
- 都可以包含抽象方法。
- 都可以有默认实现的方法(Java 8 可以用
default关键字在接口中定义默认方法)。
区别:
- 接口主要用于对类的行为进行约束。抽象类主要用于代码复用,强调所属关系。
- 接口没有构造方法,抽象类有,给子类使用。
- 类只能继承一个类,但是可以实现多个接口。
- 接口中的成员变量只能是
public static final类型的,不能被修改且必须有初始值,而抽象类的成员变量默认 default,可在子类中被重新定义,也可被重新赋值。
Object 类的常见方法有哪些?
Object 类是一个特殊的类,是所有类的父类。它主要提供了以下 11 个方法:
- getClass()
- hashCode()
- equals(Object obj)
- clone()
- toString()
- notify()、notifyAll()
- wait(long timeout)、wait(long timeout, int nanos)、wait()
- finalize()
/**
* native 方法,用于返回当前运行时对象的 Class 对象,使用了 final 关键字修饰,故不允许子类重写。
*/
public final native Class<?> getClass()
/**
* native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的HashMap。
*/
public native int hashCode()
/**
* 用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写以用于比较字符串的值是否相等。
*/
public boolean equals(Object obj)
/**
* native 方法,用于创建并返回当前对象的一份拷贝。
*/
protected native Object clone() throws CloneNotSupportedException
/**
* 返回类的名字实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。
*/
public String toString()
/**
* native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
*/
public final native void notify()
/**
* native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
*/
public final native void notifyAll()
/**
* native方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 ,timeout 是等待时间。
*/
public final native void wait(long timeout) throws InterruptedException
/**
* 多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 毫秒。。
*/
public final void wait(long timeout, int nanos) throws InterruptedException
/**
* 跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
*/
public final void wait() throws InterruptedException
/**
* 实例被垃圾回收器回收的时候触发的操作
*/
protected void finalize() throws Throwable { }
== 和 equals() 的区别
== 对于基本类型和引用类型的作用效果是不同的:
- 对于基本数据类型来说,
==比较的是值。 - 对于引用数据类型来说,
==比较的是对象的内存地址。
equals() 不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,因此所有的类都有equals()方法。
Object 类 equals() 方法:
public boolean equals(Object obj) {
return (this == obj);
}
equals() 方法存在两种使用情况:
- 类没有重写
equals()方法:等价于“==”,比较两对象的内存地址 - 类重写了
equals()方法:一般我们都重写equals()方法来比较两个对象中的内容是否相等
hashCode() 有什么用?
hashCode() 的作用是获取哈希码(int 整数),也称为散列码。这个哈希码的作用是确定该对象在哈希表中的索引位置。
为什么要有 hashCode?
当你把对象加入
HashSet时,HashSet会先计算对象的hashCode值来判断对象加入的位置,同时也会与其他已经加入的对象的hashCode值作比较,如果没有相符的hashCode,HashSet会假设对象没有重复出现。但是如果发现有相同hashCode值的对象,这时会调用equals()方法来检查hashCode相等的对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了equals的次数,相应就大大提高了执行速度。
在使用某些容器时(比如 HashMap、HashSet),hashcode会先验证对象是否相同,相等的话再调用equals(),大大减少equals()次数减少查找成本
那为什么两个对象有相同的 hashCode 值,它们也不一定是相等的?
因为 hashCode() 所使用的哈希算法也许刚好会让多个对象传回相同的哈希值。越糟糕的哈希算法越容易碰撞,但这也与数据值域分布的特性有关(所谓哈希碰撞也就是指的是不同的对象得到相同的 hashCode )。
总结下来就是:
- 如果两个对象的
hashCode值相等,那这两个对象不一定相等(哈希碰撞)。 - 如果两个对象的
hashCode值相等并且equals()方法也返回true,我们才认为这两个对象相等。 - 如果两个对象的
hashCode值不相等,我们就可以直接认为这两个对象不相等。
为什么重写 equals() 时必须重写 hashCode() 方法?
因为两个相等的对象的 hashCode 值必须是相等。也就是说如果equals方法判断两个对象是相等的,那这两个对象的hashCode 值也要相等。
如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。
String、StringBuffer和StringBuilder的异同?
相同点:底层都是通过char数组实现的
不同点:
- String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
- StringBuffer的方法使用synchronized同步锁,线程安全,在多线程系统中可以保证数据同步,但是效率稍低;
- StringBuilder线程不安全,在多线程系统中不能使用,但是效率比较高。
String:对象不可变,线程安全,适用于少量的字符串操作的情况
StringBuffer:使用synchronized同步锁,线程安全,效率稍低。适用多线程下在字符缓冲区进行大量操作的情况
StringBuilder:线程不安全,效率比较高,适用于单线程下在字符缓冲区进行大量操作的情况
反射
Java IO 流了解吗?
即Java 的输入流和输出流,根据数据的处理方式又分为字节流和字符流。
Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
-
InputStream/OutputStream。字节输入输出流基类 -
Reader/Writer。字符输入输出流基类
I/O 流为什么要分为字节流和字符流呢?
问题本质想问:不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么 I/O 流操作要分为字节流操作和字符流操作呢?
- 字符流是由 Java 虚拟机将字节转换得到的,这个过程还算是比较耗时;
- 如果我们不知道编码类型的话,使用字节流的过程中很容易出现乱码问题。
有哪些常见的 IO 模型?
UNIX 系统下, IO 模型一共有 5 种:同步阻塞 I/O、同步非阻塞 I/O、I/O 多路复用、信号驱动 I/O 和异步 I/O。
Java 中 3 种常见 IO 模型
BIO、NIO、AIO
BIO (Blocking I/O)
BIO 属于同步阻塞 IO 模型 。
应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。高并发场景下性较差
NIO (Non-blocking/New I/O)
可以看作是 I/O 多路复用模型。
我们先来看看 同步非阻塞 IO 模型。
同步非阻塞 IO 模型中,应用程序会发起轮询 read 调用,直到内核数据准备好,期间不阻塞。等待数据从内核空间拷贝到用户空间期间,线程是阻塞的,直到在内核把数据拷贝到用户空间。
- 阻塞减少但耗费资源
这个时候,I/O 多路复用模型 就上场了。
IO 多路复用模型中,线程首先发起 select 调用,询问内核数据是否准备就绪,等内核把数据准备好了,用户线程再发起 read 调用。read 调用的过程(数据从内核空间 -> 用户空间)还是阻塞的。
- 支持 IO 多路复用的系统调用,有 select,epoll 等等。
- 减少了对 CPU 资源的消耗。
Java 中的 NIO ,有一个非常重要的选择器 ( Selector ) 的概念,也可以被称为 多路复用器。通过它,只需要一个线程便可以管理多个客户端连接。当客户端数据到了之后,才会为其服务。
AIO (Asynchronous I/O)
AIO 也就是 NIO 2。是异步 IO 模型。
异步 IO 是基于事件和回调机制实现的,发起read之后直接返回,不会堵塞在那里,当后台处理完成,操作系统会回调,通知线程进行后续的操作。
目前来说 AIO 的应用还不是很广泛。Netty 之前也尝试使用过 AIO,不过又放弃了。这是因为,Netty 使用了 AIO 之后,在 Linux 系统上的性能并没有多少提升。
最后,来一张图,简单总结一下 Java 中的 BIO、NIO、AIO。
集合
Connection接口:
— List 有序,可重复
- ArrayList
- 优点: 底层数据结构是object[]数组,查询快,增删慢(向数组末尾添加元素快)。
- 缺点: 线程不安全,效率高
- 初始容量10,扩容1.5倍
- Vector
- 优点: 底层数据结构是数组,查询快,增删慢。
- 缺点: 线程安全,效率低
- LinkedList
- 优点: 底层数据结构是链表,查询慢,增删快。
- 缺点: 线程不安全,效率高
—Set 无序,不可重复
-
HashSet
- 底层数据结构是哈希map。(无序,不可重复)初始容量16,扩容两倍
- 如何来保证元素唯一性?
- 依赖两个方法:hashCode()和equals()
-
LinkedHashSet
- 底层数据结构是链表和哈希表。(FIFO插入,有序,不可重复)
- 链表保证元素有序
- 哈希表保证元素唯一
-
TreeSet
- 底层数据结构是红黑树。(有序,不可重复)
-
- 如何保证元素排序的呢?
- 自然排序、比较器排序
- 2.如何保证元素唯一性的呢?
- 根据比较的返回值是否是0来决定
针对Collection集合我们到底使用谁呢?
如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
如果你知道用集合,就用ArrayList。
原文链接:blog.csdn.net/zhangqunshu…
Map接口有三个比较重要的实现类,分别是HashMap、HashTable、TreeMap。
TreeMap是有序的,HashMap和HashTable是无序的。 Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。 这就意味着:
Hashtable是线程安全的,HashMap不是线程安全的。 HashMap效率较高,Hashtable效率较低。 如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。 查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有 synchronized关键字,而HashMap的源码中则没有。 Hashtable不允许null值,HashMap允许null值(key和value都允许) 父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap
-
HashMap
- 无序
- 线程不安全、方法不同步、效率较高
- kv都允许为null
- 如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap
-
HashTable
- 无序
- 线程安全(方法都有synchronized关键字)、方法同步、效率较低
- 不允许为null
-
TreeMap
- 有序