final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。
题8:如何理解 final 关键字?
1)类的final变量和普通变量有什么区别?
当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。
2)被final修饰的引用变量指向的对象内容可变吗?
引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的
3)final参数的问题
在实际应用中,我们除了可以用final修饰成员变量、成员方法、类,还可以修饰参数、若某个参数被final修饰了,则代表了该参数是不可改变的。如果在方法中我们修改了该参数,则编译器会提示你:
The final local variable i cannot be assigned. It must be blank and not using a compound assignment。
java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响。
题9:为什么 String 类型是被 final 修饰的?
1、为了实现字符串池
final修饰符的作用:final可以修饰类,方法和变量,并且被修饰的类或方法,被final修饰的类不能被继承,即它不能拥有自己的子类,被final修饰的方法不能被重写, final修饰的变量,无论是类属性、对象属性、形参还是局部变量,都需要进行初始化操作。
String为什么要被final修饰主要是为了”安全性“和”效率“的原因。
final修饰的String类型,代表了String不可被继承,final修饰的char[]代表了被存储的数据不可更改性。虽然final修饰的不可变,但仅仅是引用地址不可变,并不代表了数组本身不会改变。
为什么保证String不可变呢?
因为只有字符串是不可变,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现,反之变量改变它的值,那么其它指向这个值的变量值也会随之改变。
如果字符串是可变,会引起很严重的安全问题。如数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接或在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则改变字符串指向的对象值,将造成安全漏洞。
2、为了线程安全
因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
3、为了实现String可创建HashCode不可变性
因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。使得字符串很适合作为Map键值对中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。
题10:接口(interface)和抽象类(abstract class)有什么区别?
默认方法
抽象类可以有默认的方法实现;而接口类在JDK1.8之前版本,不存在方法的实现。
实现方式
抽象类子类使用extends关键字来继承抽象类,如果子类不是抽象类,子类需要提供抽象类中所声明方法的实现;而接口类子类使用implements来实现接口,需要提供接口中所有声明的实现。
构造器
抽象类中可以有构造器;而接口中不能有构造器。
和正常类区别
抽象类不能被实例化;而接口是完全不同的类型。
访问修饰符
抽象类中抽象方法可以有public、protected、default等修饰;而接口类默认是public,不能使用其他修饰符。
多继承
抽象类一个子类只能存在一个父类;而接口类一个子类可以存在多个接口。
添加新方法
抽象类中添加新方法,可以提供默认的实现,因此可以不修改子类现有的代码;而接口类中添加新方法,则子类中需要实现该方法。
题11:面向过程与面向对象有什么区别?
面向过程
性能相比面向对象高,因其类调用时需要实例化,开销比较大,消耗资源,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
面向对象
易维护、复用以及扩展,由于面向对象有封装、继承、多态性等特征,可以设计出低耦合、高内聚的系统,使得更加灵活,易于维护。
题12:Java 编程语言有哪些特点?
1)简单易学;
2)面向对象(封装,继承,多态);
3)平台无关性(Java虚拟机实现平台无关性);
4)可靠性;
5)安全性;
6)支持多线程;
7)支持网络编程并方便易用;
8)编译与解释并存。
题13:重载和重写有什么区别?
重载(Overload) 是指让类以统一的方式处理不同类型数据的一种手段,实质表现就是多个具有不同的参数个数或者不同类型的同名函数,存在于同一个类中,返回值类型不同,是一个类中多态性的一种表现。
调用方法时通过传递不同参数个数和参数类型来决定具体使用哪个方法的多态性。
重写(Override) 是指父类与子类之间的多态性,实质就是对父类的函数进行重新定义。
如果子类中定义某方法与其父类有相同的名称和参数则该方法被重写,需注意的是子类函数的访问修饰权限不能低于父类的。
如果子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法,如需父类中原有的方法则可使用super关键字。
题14:静态方法和实例方法有什么不同?
静态方法和实例方法的区别主要体现在两个方面:
其一在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式而实例方法只能试用后面这种方式。也就是说,调用静态方法可以无需创建对象进行实例化。
其二静态方法在访问本类的成员时,只允许访问静态成员也就是静态成员变量和静态方法,而不允许访问实例成员变量和实例方法,实例方法是没有这个限制的。
题15:== 和 equals 两者有什么区别?
使用==比较
用于对比基本数据类型的变量,是直接比较存储的 “值”是否相等;
用于对比引用类型的变量,是比较的所指向的对象地址。
使用equals比较
equals方法不能用于对比基本数据类型的变量;
如果没对Object中equals方法进行重写,则是比较的引用类型变量所指向的对象地址,反之则比较的是内容。
题16:Integer 和 int 两者有什么区别?
Integer是int的包装类,默认值是null;int是基本数据类型,默认值是0;
Integer变量必须实例化后才能使用;int变量不需要;
Integer实际是对象的引用,指向此new的Integer对象;int是直接存储数据值。
分析总结
1)Integer与new Integer不相等。new出来的对象被存放在堆,而非new的Integer常量则在常量池,两者内存地址不同,因此判断是false。
2)两个值都是非new Integer,如果值在-128,127区间,则是true,反之为false。
这是因为java在编译Integer i2 = 128时,被翻译成:
Integer i2 = Integer.valueOf(128);
而valueOf()函数会对-128到127之间的数进行缓存。
3)两个都是new Integer,两者判断为false,内存地址不同。
4)int和Integer对比不管是否new对象,两者判断都是true,因为会把Integer自动拆箱为int再去比。
题17:什么是 Java 内部类?
内部类是指把A类定义在另一个B类的内部。
例如:把类User定义在类Role中,类User就被称为内部类。
class Role {
class User {
}
}
1、内部类的访问规则
1)可以直接访问外部类的成员,包括私有
2)外部类要想访问内部类成员,必须创建对象
2、内部类的分类
1)成员内部类
2)局部内部类
3)静态内部类
4)匿名内部类
题18:什么是自动装箱?什么是自动拆箱?
自动装箱是指将基本数据类型重新转化为对象。
public class Test {
public static void main(String[] args) {
Integer num = 9;
}
}
num = 9的值是属于基本数据类型,原则上不能直接赋值给对象Integer。但是在JDK1.5版本后就可以进行这样的声明自动将基本数据类型转化为对应的封装类型,成为对象后可以调用对象所声明的方法。
自动拆箱是指将对象重新转化为基本数据类型。
public class Test {
public static void main(String[] args) {
// 声明Integer对象
Integer num = 9;
// 隐含自动拆箱
System.out.print(num–);
}
}
由于对象不能直接进行运算,而是需要转化为基本数据类型后才能进行加减乘除。
// 装箱
Integer num = 10;
// 拆箱
int num1 = num;
题19:JDK1.8 中 ConcurrentHashMap 不支持空键值吗?
首先明确一点HashMap是支持空键值对的,也就是null键和null值,而ConcurrentHashMap是不支持空键值对的。
查看一下JDK1.8源码,HashMap类部分源码,代码如下:
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
HashMap在调用put()方法存储数据时会调用hash()方法来计算key的hashcode值,可以从hash()方法上得出当key==null时返回值是0,这意思就是key值是null时,hash()方法返回值是0,不会再调用key.hashcode()方法。
ConcurrentHashMap类部分源码,代码如下:
public V put(K key, V value) {
return putVal(key, value, false);
}
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;😉 {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}
ConcurrentHashmap在调用put()方法时调用了putVal()方法,而在该方法中判断key为null或value为null时抛出空指针异常NullPointerException。
ConcurrentHashmap是支持并发的,当通过get()方法获取对应的value值时,如果指定的键为null,则为NullPointerException,这主要是因为获取到的是null值,无法分辨是key没找到null还是有key值为null。
题20:父类中静态方法能否被子类重写?
父类中静态方法不能被子类重写。
重写只适用于实例方法,不能用于静态方法,而且子类当中含有和父类相同签名的静态方法,一般称之为隐藏。
public class A {
public static String a = “这是父类静态属性”;
public static String getA() {
return “这是父类静态方法”;
}
}
public class B extends A{
public static String a = “这是子类静态属性”;
public static String getA() {
return “这是子类静态方法”;
}
public static void main(String[] args) {
A a = new B();
System.out.println(a.getA());
}
}
如上述代码所示,如果能够被重写,则输出的应该是“这是子类静态方法”。与此类似的是,静态变量也不能被重写。如果想要调用父类的静态方法,应该使用类来直接调用。
题1:Java 中常用的集合有哪些?
Map接口和Collection接口是所有集合框架的父接口
Collection接口的子接口包括:Set接口和List接口。
Set中不能包含重复的元素。List是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式。
Map接口的实现类主要有:HashMap、Hashtable、ConcurrentHashMap以及TreeMap等。Map不能包含重复的key,但是可以包含相同的value。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。
Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
Iterator所有的集合类,都实现了Iterator接口,这是一个用于遍历集合中元素的接口,主要包含以下三种方法:
hasNext()是否还有下一个元素
next()返回下一个元素
remove()删除当前元素
题2:为什么 Map 接口不继承 Collection 接口?
1)Map提供的是键值对映射(即Key和value的映射),而Collection提供的是一组数据并不是键值对映射。
2)若果Map继承了Collection接口,那么所实现的Map接口的类到底是用Map键值对映射数据还是用Collection的一组数据呢?比如平常所用的hashMap、hashTable、treeMap等都是键值对,所以它继承Collection是完全没意义,而且Map如果继承Collection接口的话,违反了面向对象的接口分离原则。
接口分离原则:客户端不应该依赖它不需要的接口。
另一种定义是类间的依赖关系应该建立在最小的接口上。
接口隔离原则将非常庞大、臃肿的接口拆分成为更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。
接口隔离原则的目的是系统解开耦合,从而容易重构、更改和重新部署,让客户端依赖的接口尽可能地小。
3)Map和List、Set不同,Map放的是键值对,List、Set存放的是一个个的对象。说到底是因为数据结构不同,数据结构不同,操作就不一样,所以接口是分开的,还是接口分离原则。
题3:Collection 和 Collections 有什么区别?
java.util.Collection是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java类库中有很多具体的实现。
Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。其直接继承接口有List与Set。
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
java.util.Collections是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
题4:ArrayList 和 LinkedList 有什么区别?
1)ArrayList是Array动态数组的数据结构,LinkedList是Link链表的数据结构,此外,它们两个都是对List接口的实现。前者是数组队列,相当于动态数组;后者为双向链表结构,也可当作堆栈、队列、双端队列。
2)当随机访问List时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
3)当对数据进行增加和删除的操作时(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。
4)从利用效率来看,ArrayList自由性较低,因为它需要手动设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。
5)ArrayList主要控件开销在于需要在List列表预留一定空间;而LinkList主要控件开销在于需要存储结点信息以及结点指针信息。
题5:HashMap 和 HashTable 有什么区别?
Hashtable是线程安全,而HashMap则非线程安全。
Hashtable所有实现方法添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合。
HashMap允许使用null作为key,不过建议还是尽量避免使用null作为key。HashMap以null作为key时,总是存储在table数组的第一个节点上。而Hashtable则不允许null作为key。
HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。
HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。
HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。
HashMap和Hashtable的底层实现都是数组+链表结构实现。
题6:HashMap 是怎么扩容的?
当HashMap中元素个数超过数组大小*loadFactor时,需进行数组扩容。
loadFactor默认值为0.75,默认情况下,数组大小为16,HashMap中元素个数超过16 * 0.75=12的时,就把数组的大小扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以能够预选知道HashMap中元素的个数,应该预设数组的大小,可以有效的提高HashMap的性能。
假设有1000个元素new HashMap(1000),理论上来讲new HashMap(1024)更合适,不过上面已经提过即使是1000个元素,HashMap也会自动设置为1024。但是new HashMap(1024),而0.75*1024 <1000, 为了可以0.75 * size >1000,必须new HashMap(2048),避免了resize的问题。
总结:
添加元素时会检查容器当前元素个数。当HashMap的容量值超过临界值(默认16 * 0.75=12)时扩容。HashMap将会重新扩容到下一个2的指数幂(16->32->64)。调用resize方法,定义长度为新长度(32)的数组,然后对原数组数据进行再Hash。注意的是这个过程比较损耗性能。
题7:JDK1.8 和 JDK1.7 中 ArrayList 的初始容量多少?
JDK1.7下ArrayList()初始化后的默认长度是10,源码如下:
//无参构造方法
public ArrayList() {
this(10);
}
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
通过上述源代码可以看出,默认的构造方法中直接指定数组长度为10,同时调用重载的构造方法,创建了长度为10的一个数组。
题8:JDK1.8下ArrayList()初始化后的默认长度是0,源码如下:
//无参构造方法
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
构造方法中静态类型的数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}是个空数组,数组长度为0,因此JDK1.8下的ArrayList()初始化后默认的数组长度为0。
题8:Arrays.asList() 有什么使用限制?
1)Arrays.asList()方法不适用于基本数据类型
byte
short
int
long
float
double
boolean
2)Arrays.asList()方法把数组与列表链接起来,当更新其中之一时,另一个自动更新。
3)Arrays.asList()方法不支持add和remove方法。
题9:Set 为什么是无序的?
Set系列集合添加元素无序的根本原因是底层采用哈希表存储元素。
JDK1.8以下版本:哈希表 = 数组 + 链表 + (哈希算法)
JDK1.8及以上版本:哈希表 = 数组 + 链表 + 红黑树 + (哈希算法)
当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
题10:Comparable 和 Comparator有什么区别?
Comparable接口出自java.lang包,它有一个compareTo(Object obj)方法用来排序。
Comparator接口出自java.util包,它有一个compare(Object obj1, Object obj2)方
法用来排序。
一般对集合使用自定义排序时,需要重写compareTo()方法或compare()方法。
当需要对某一个集合实现两种排序方式,比如一个用户对象中的姓名和身份证分别采用一种排序方法。
方式一:重写compareTo()方法实现姓名、身份证排序
方式二:使用自定义的Comparator方法实现姓名、身份证排序
方法三:使用两个Comparator来实现姓名、身份证排序
其中方式二代表只能使用两个参数的形式Collections.sort()。
Collections是一个工具类,sort是其中的静态方法,是用来对List类型进行排序的,它有两种参数形式:
public static <T extends Comparable<? super T>> void sort(List list) {
list.sort(null);
}
public static void sort(List list, Comparator<? super T> c) {
list.sort©;
}
题1:什么是并发?
并发是针对服务器而言,是否并发的关键是看用户操作是否对服务器产生了影响。并发是指在同一时刻与服务器进行了交互的在线用户数量。这些用户的最大特征是和服务器产生了交互,这种交互既可以是单向的传输数据,也可以是双向的传送数据。
题2:什么是进程?
进程是指运行中的应用程序,每个进程都有自己独立的地址空间(内存空间)。
比如用户点击桌面的IE浏览器,就启动了一个进程,操作系统就会为该进程分配独立的地址空间。当用户再次点击左边的IE浏览器,又启动了一个进程,操作系统将为新的进程分配新的独立的地址空间。目前操作系统都支持多进程。
题3:什么是线程?
进程是表示自愿分配的基本单位。而线程则是进程中执行运算的最小单位,即执行处理机调度的基本单位。
通俗来讲:一个程序有一个进程,而一个进程可以有多个线程。
题4:并发和并行有什么区别?
并行(parallellism)是指两个或者多个事件在同一时刻发生,而并发(parallellism)是指两个或多个事件在同一时间间隔发生。
并行是在不同实体上的多个事件,而并发是在同一实体上的多个事件。
并行是在一台处理器上同时处理多个任务(Hadoop分布式集群),而并发在多台处理器上同时处理多个任务。
题5:进程与线程之间有什么区别?
进程是系统中正在运行的一个程序,程序一旦运行就是进程。
进程可以看成程序执行的一个实例。进程是系统资源分配的独立实体,每个进程都拥有独立的地址空间。一个进程无法访问另一个进程的变量和数据结构,如果想让一个进程访问另一个进程的资源,需要使用进程间通信,比如管道,文件,套接字等。
一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。线程与进程的一个主要区别是,统一进程内的一个主要区别是,同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。同时,每个线程还拥有自己的寄存器和栈,其他线程可以读写这些栈内存。
线程是进程的一个实体,是进程的一条执行路径。
线程是进程的一个特定执行路径。当一个线程修改了进程的资源,它的兄弟线程可以立即看到这种变化。
题1:什么是 Elasticsearch?
ES是一种开源、RESTful、可扩展的基于文档的搜索引擎,它构建在Lucene库上。
用户使用Kibana就可以可视化使用数据,同时Kibana也提供交互式的数据状态呈现和数据分析。
Apache Lucene搜索引擎基于JSON文档来进行搜索管理和快速搜索。
Elasticsearch,可简称为ES(官方未给出简称名字,很多人都这么叫而已)一种开源、RESTful、可扩展的基于文档的搜索引擎,构建是在Apache Lucene库的基础上的搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。 但是,Lucene只是一个库。想要发挥其强大的作用,需使用Java并要将其集成到应用中。
Elasticsearch是使用Java编写并使用Lucene来建立索引并实现搜索功能,但是它的目的是通过简单连贯的RESTful API让全文搜索变得简单并隐藏Lucene的复杂性。
用户通过JSON格式的请求,使用CRUD的REST API就可以完成存储和管理文本、数值、地理空间、结构化或者非结构化的数据。
Elasticsearch不仅是Lucene和全文搜索引擎,它还提供:
1、分布式的实时文件存储,每个字段都被索引并可被搜索
2、实时分析的分布式搜索引擎
3、可以扩展到上百台服务器,处理PB级结构化或非结构化数据,而且所有的这些功能被集成到一台服务器,应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。
Elasticsearch非常简单,它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。Elasticsearch在Apache 2 license下许可使用,可以免费下载、使用和修改。
题2:Elasticsearch 安装前需要什么环境?
ElasticSearch是基于lucence开发的,也就是运行时需要java jdk支持。所以要先安装JAVA环境。
注意:由于ElasticSearch 5.x往后依赖于JDK 1.8及以上版本,安装高版本ES需要考虑与JDK版本的兼容性问题。
题3:ElasticSearch 的节点类型有什么区别?
节点是指ElasticSearch的实例。当启动Elasticsearch的实例,就会启动至少一个节点。
相同集群名的多个节点的连接就组成了一个集群,在默认情况下,集群中的每个节点都可以处理http请求和集群节点间的数据传输,集群中所有的节点都知道集群中其他所有的节点,可以将客户端请求转发到适当的节点。
节点有以下类型:
主(master)节点:在一个节点上当node.master设置为True(默认)的时候,它有资格被选作为主节点,控制整个集群。
数据(data)节点:在一个节点上node.data设置为True(默认)的时候。该节点保存数据和执行数据相关的操作,如增删改查,搜索,和聚合。
客户端节点:当一个节点的node.master和node.data都设置为false的时候,它既不能保持数据也不能成为主节点,该节点可以作为客户端节点,可以响应用户的情况,并把相关操作发送到其他节点。
部落节点:当一个节点配置tribe.*的时候,它是一个特殊的客户端,它可以连接多个集群,在所有连接的集群上执行搜索和其他操作。