Java知识点
1.迭代器
迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必知道或关心该序列底层的结构。如Java的Iterator,它只能单向移动,只能用来:(1)使用方法iterator()要求容器返回一个Iterator,Iterator将准备好返回序列的第一个元素。(2)使用next()获得序列中的下一个元素。(3)使用hasNext()检查序列中是否还有元素。(4)使用remove()将迭代器新近返回的元素删除。
Iterator还可以移除由next()产生的最后一个元素,这意味着在调用remove()之前必须先调用next()。
ListIterator是一个更强大的Iterator的值类型,它只能用于各种List类的访问。尽管Iterator只能向前移动,但是ListIterator可以双向移动。可以指向当前位置的前一个和后一个元素的索引,并可以使用set()方法替换它访问过的最后一个元素。可以通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
2.Stack
“栈”通常是指“后进先出”的容器。LinkedList具有能够直接实现栈的所有功能的方法。使用peek()方法提供栈顶元素,但并不将其从栈顶移除,而pop()将移除并返回栈顶元素。push()将元素加入栈。
类名之后的<T>告诉编译器这将是一个参数化类型,而其中的类型参数,即在类被使用时将会被实际类型替换的参数,就是T。
3.Queue
队列是一个典型的先进先出的容器。它常被当作一种可靠的将对象从程序的某个区域传输到另外一个区域的途经。队列在并发编程中特别重要,因为它们可以安全地将对象从一个任务传输给另一个任务。
offer()方法是与Queue相关的方法之一,它在允许的情况下,将一个元素插入到队尾,或者返回false。poll()和remove()方法将移除并返回队头,但poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常。
PriorityQUEUE可以确保当你调用peek()、poll()和remove()方法时,获取的元素将是队列中优先级最高的元素。
4.数组将数字与对象联系起来。数组一旦生成,其容量就不能改变。如果要进行大量的随机访问,就是用ArrayList;如果要经常从表中间插入或删除元素,则应该使用LinkedList。新程序中不应该使用过时的Vector、Hashtable和Stack。
5.所有的类都是在对其第一次使用时,动态加载到JVM中的。构造器也是类的静态方法。static子句在类第一次被加载时执行。
forName()是取得Class对象的引用的一种方法。它是用一个包含目标类的文本名的String作为输入参数,返回的是一个Class对象的引用。
仅使用.class语法来获得对类的引用不会引发初始化。如果一个static域不是final的,那么在对它访问时,总是要求在它被读取之前,要求进行链接(为这个域分配存储空间)和初始化(初始化该存储空间)。
关键字instanceof返回一个布尔值,告诉我们对象是不是某个特定类型的实例。
6.网络编程
1)端口并不是机器上一个物理上存在的场所,而是一种软件抽象。请求一个特定的端口,相当于请求与那个端口编号关联的服务。通常,每个服务都同一台特定服务器机器上的一个独一无二的端口编号关联在一起。
2)“套接字”或者“插座”(Socket)也是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;以及Socket,客户用它初始一次连接。
3)侦听套接字只能接收新的连接请求,不能接收实际的数据包。
4)创建一个ServerSocket 时,只需为其赋予一个端口编号。不必把一个IP 地址分配它,因为它已经在自己代表的那台机器上了。但在创建一个Socket 时,却必须同时赋予IP 地址以及要连接的端口编号(另一方面,从ServerSocket.accept()返回的Socket 已经包含了所有这些信息)。
5)调用accept()时,方法会暂时陷入停顿状态(堵塞),直到某个客户尝试同它建立连接。尽管它在那里等候连接,但其他进程仍能正常运行。建好一个连接以后,accept()就会返回一个Socket对象,它是那个连接的代表。
7.内部类的方法可以访问它的外部类的实例变量。内部类通过它的外部类实例也能调用外部类的方法。
要声明一个接口,要提供方法头,不需要实现这些方法,而接口的所有方法默认为公有方法,不必声明方法为public。接口的实现类必须将接口方法声明为public,否则,默认情况下,它们在包级别可访问。
定义在接口中的任何变量自动为public static final。在接口中,你无法拥有实例变量,接口指定行为,而不是状态。
Arrays.sort()不区分带瞎写地对字符串进行排序的调用方法(注意第二参数lambda表达式的应用):
String strings[]={"xu","Da","song"}; Arrays.sort(strings,(x,y)->x.compareToIgnoreCase(y));
操作符 :: 将方法名称与类或对象名称分隔开,具体有三种使用方式,1)类::实例方法2)类::静态方法3)对象::实例方法。如:
System.out::println 而 String::compareToIgnoreCase等同于(x,y)->x.compareToIgnoreCase(y)
用@FunctionalInterface注解标记函数式接口,这样做的好处一是,编译器会检查出被注解实体是一个带有单个抽象方法的接口;二是,javadoc页面会包含该接口是函数式接口的声明。
8.在lambda表达式中不允许声明一个与局部变量同名的参数或局部变量。
子类的构造函数不能访问父类的私有变量,必须通过父类的构造函数来初始化它们,如通过关键字super来调用父类的构造函数。注:父类构造函数调用必须是子类的构造函数中的第一条语句。例:
public Manger(String name,double salary){ super(name,salary);//调用父类的构造函数 bonus=0; }
使用instanceof操作符,可以让父类应用转化为子类引用。将一个方法声明为final时,子类不可以覆盖它。
9.一个抽象类可以拥有非抽象方法。不同于接口,抽象类可以拥有实例变量和构造函数。
构造抽象类的实例是不可能的,但可以拥有一个类型为抽象类的变量,前提是该变量引用一个具体子类的对象。例:
//Person 是一个抽象类 Person p=new Person("Fred");//错误 //Student是Person的实现子类 Person p=new Student("Fred");//可行
父类的实现优于接口的实现。
10.当与null比较时,所有的equals方法都返回false。
11.数据类型转换要注意的细节:
1) 凡是byte、short 、 char数据类型数据在运算的时候都会自动转换成int类型的数据再运算。
2) 两个不同数据类型的数据在运算的时候,结果取决于大的数据类型。
12.后自增在jvm的运行原理:
因为后自增要使用 到没有+1之前 的值,那么jvm会先声明一个变量用于保存没有+1之前的值。如i++;
则:1). int temp = i; // 声明了一个临时变量用于记录了i没有加1之前的值。
2). 自增。 i = i+1; i = 1;3). temp把用作了表达式 的结果。
13.算术运算符:
+ (正数、加法、连接符)
连接符的作用: 让任何的数据都可以与字符串进行拼接。
如果+号用于字符串的时候,那么+号就是一个连接符,并不是 做加法功能了。
连接符要注意:任何类型的数据与字符串使用连接符连接,那么结果都是字符串类型的数据。
/ (除法)
%(取模、取余数)
注:1)计算机每次运算的时候只能取两个数据运算。如:System.out.println(1+2+3 +" world"+1+2+3); 输出为:6world123。
2) 在java中做取模运算时,结果的正负号是取决于被除数。如: System.out.println("结果:"+(10%-3));输出为1。System.out.println("结果:"+(-10%3));输出为-1。System.out.println("结果:"+(-10%-3)); 输出为-1。
14.比较运算符: 比较运算符的结果都是返回一个布尔值的。
== (判断是否等于)
==用于比较两个基本数据类型数据的时候,比较的是两个变量所存储的值是否一致.
==用于比较两个引用类型变量的数据时候,比较的是两个 引用类型变量所记录的内存地址是否一致.
两个不同类型的数据是否可以比较呢.,可以的,但是两个不同类型的数据必须是兼用的数据。例如 byte b = 10; long l = 30; System.out.println(l>b);输出为true。两者都是整数类型,比较的过程会先把b转换了long类型的数据,然后再进行比较 。
15. 1)短路与(&&)和单与(&)符号的相同与不同点:
相同点: 短路与和单与运算 的结果是一样的。
不同点: 使用短路与的时候,如果左边的布尔表达式为false,则不会在运算右边的布尔表达式,从而提高了效率。使用单与的时候,即使发现左边的布尔表达式为false,还是会运算右边的布尔表达式的。
只有左边的布尔表达式为false时,双与的效率才要高于单与的。
2)短路或与单或的相同点与不同点:
相同点:运算的结果是一致 的。不同点:使用短路或的时候,当发现左边的布尔表达式为true时,则不会运算右边的布尔表达式。
使用单或的时候发现左边的布尔表达式为true,还是会运算右边布尔表达式。
16.位运算符:位运算符就是直接操作二进制位的。
& (与);| (或);^ (异或);~ (取反)
规律: 如果操作数A连续异或同一个操作数两次,那么结果还是操作数A。该规律可应用: 对数据加密。
17.移位运算符:
<<(左移)
规律:一个操作数进行左移运算的时候,结果就是等于操作数乘以2的n次方,n就是左移 的位数。如:
3<<1 = 3 *2(1) = 6; 3<<2 = 3*2(2) = 12;3<<3 = 3*2(3) = 24
>>(右移)规律:一个操作数在做右移运算的时候,实际上就是等于该操作数除以2的n次方,n就是右移的位数。如:
3>>1 = 3 / 2(1) = 1;3>>2 = 3 / 2(2) = 0 。
>>>(无符号右移) :无符号右移与右移的区别:进行右移运算的时候,如果操作数是一个正数,那么左边的空缺位使用0补,如果操作数是一个负数,那么左边的空缺位使用1补。而使用无符号右移的时候,不管是正数还是负数都统一使用0补。18.三元运算符(三目运算符)
格式: 布尔表达式?值1:值2 ;
三元运算符要注意的细节:
即使用三元运算符的时候,一定要使用该表达式返回的结果,或者是定义一个变量接收该表达式返回的结果。
19.switch语句要注意的事项:
1) switch语句使用的变量只能是byte、 char、 short、int、 String数据类型,String数据类型是从jdk7.0的时候开始支持的。
2) case后面跟的数据必须是一个常量。
3) switch的停止条件:
switch语句一旦匹配上了其中的一个case语句,那么就会执行对应的case中的语句代码,执行完毕之后如果没有遇到break关键字或者是结束switch语句的大括号,那么switch语句不会再判断,按照代码的顺序从上往下执行所有的代码。直到遇到break或者是结束siwitch语句的大括号为止。
4) 在switch语句中不管代码的顺序如何,永远都是会先判断case语句,然后没有符合的情况下才会执行default语句。
20.while循环语句要注意的事项:
1) while循环语句一般是通过一个变量控制其循环的次数。
2) while循环语句的循环体代码如果只有一个语句的时候,那么可以省略大括号。但是也是不建议大家省略。
3) while循环语句的判断条件后面不能跟有分号,否则会影响到执行的效果。
21.转义字符:特殊字符使用”\”把其转化成字符的本身输出,那么使用”\”的字符称作为转移字符。
常见的转义字符有:
\b Backspace (退格键)
\t Tab 制表符(制表符的作用就是为了让一列对齐) 一个tab一般等于四个空格。
\n 换行
\r 回车 把光标移动到一行的首位置上。
注意: 如果是在windows系统上操作文件的时候需要换行,是需要\r\n一起使用的;如果是在其他的操作系统上需要换行,仅需要\n即可。如:
File file = new File("F:\\a.txt"); FileWriter out = new FileWriter(file); out.write("大家好\r\n"); out.write("你们好"); out.close();
22.如果一个函数的返回值类型是具体的数据类型,那么该函数就必须要保证在任意情况下都保证有返回值(除了返回值类型是void以外)。
return 关键字的作用:
1) 返回数据给函数的调用者。
2) 函数一旦执行到了return关键字,那么该函数马上结束。 (能结束一个函数)
注意:一个函数的返回值类型 是void,那么也可以出现return关键字,但是return关键字的后面不能有数据。
break关键字与return关键字的区别:
1) break关键字是结束一个循环。
2) return关键字是结束一个函数。例如:
public static void print(){ for(int i = 0 ; i < 5; i++){ System.out.println("hello world"); ///break; //结束了当前的循环 return ; //结束当前的函数 } //使用break,能输出:"哈哈我能执行吗??";而使用return时,不能输出:"哈哈我能执行吗??" System.out.println("哈哈我能执行吗??"); }23.函数重载的作用: 同一个函数名可以出现了不同的函数,以应对不同个数或者不同数据类型的参数。
函数重载的要求:
1) 函数名一致。
2.)形参列表不一致。(形式参数的个数或者是对应的数据类型不一致)
3) 与函数的返回值类型是无关的。
24. 1)栈内存的特点:
栈内存存储的都是局部变量,变量一旦出了自己的作用域,那么马上会从内存中消失,释放内存空间。
2)堆内存的特点:
堆内存存储的都是对象数据,对象一旦被使用完,并不会马上从内存中消失,而是等待垃圾回收器不定时把垃圾对象回收,这时候该对象才会消失,释放内存。
3)凡是以new关键字创建的对象,jvm都会在堆内存中开辟一个新的空间,创建一个新的对象。
4)对象如果没有变量引用了,那么该对象就是一个垃圾对象。
25. 数组:数组是存储同一种数据类型数据的集合容器。
数组的定义格式:
数据类型[] 变量名 = new 数据类型[长度];
分析数组:
左边: int[] arr 声明了一个int类型的的数组变量,变量名为arr。
int : 表示该数组容器只能存储int类型的数据。
[] : 这是一个数组类型。
arr : 变量名.
右边:new int[50]; 创建了一个长度为50的int类型数组对象。
new : 创建数组对象的关键字。
int: 表示该数组对象只能存储int类型数据。
[]: 表示是数组类型。
50 : 该数组最多能存储50个数据。数组的容量。
等号=:是把数组对象内存地址赋予给arr变量。
数组的好处: 对分配到数组对象中每一个数据都分配一个编号(索引值、角标、下标),索引值的范围是从0开始,最大是: 长度-1。
局部变量: 如果一个变量是在一个方法(函数)的内部声明的,那么该变量就是一个局部变量。成员变量: 成员变量就是定义在方法之外,类之内的.
数组中最常见的问题:
1) NullPointerException 空指针异常
原因: 引用类型变量没有指向任何对象,而访问了对象的属性或者是调用了对象的方法。如:
int[] arr = new int[2]; arr = null ; //null 让该变量不要引用任何的对象。 不要记录任何 的内存地址。 arr[1] = 10; System.out.println(arr[1]);2) ArrayIndexOutOfBoundsException 索引值越界。
原因:访问了不存在的索引值。
数组的特点:
1) 数组只能存储同一种 数据类型的数据。
2) 数组是会给存储到数组中 的元素分配一个索引值的,索引值从0开始,最大的索引值是length-1;
3.)数组一旦初始化,长度固定。
4) 数组中的元素与元素之间的内存地址是连续的。
26.成员变量与局部变量的区别:
定义的位置上区别:
1. 成员变量是定义在方法之外,类之内的。
2. 局部变量是定义在方法之内。
作用上的区别:1. 成员变量的作用是用于描述一类事物的公共 属性的。
2. 局部变量的作用就是提供一个变量给方法内部使用而已。
生命周期区别:1) 随着对象 的创建而存在,随着对象的消失而消失。
2) 局部变量在调用了对应的方法时执行到了创建该变量的语句时存在,局部变量一旦出了自己的作用域那么马上从内存中消失。
初始值的区别:
1) 成员变量是有默认的初始值。
数据类型 默认的初始值
int 0
float 0.0f
double 0.0
boolean false
char ' '
String(引用数据类型) null
2)局部变量是没有默认的初始值的,必须要先初始化才能使用。
27.匿名对象:没有引用类型变量指向的对象称作为匿名对象。
匿名对象要注意的事项:1) 我们一般不会给匿名对象赋予属性值,因为永远无法获取到。
2) 两个匿名对象永远都不可能是同一个对象。
匿名对象好处:1)简化书写。
2)没有创建引用类型变量,所以执行完就会被垃圾回收器回收,节省内存空间。
匿名对象的应用场景:1)如果一个对象需要调用一个方法一次的时候,而调用完这个方法之后,该对象就不再使用了,这时候可以使用匿名对象。
2)可以作为实参调用一个函数。
28. 权限修饰符:权限修饰符就是控制变量可见范围的。
public : 公共的。 public修饰的成员变量或者方法任何人都可以直接访问。private : 私有的, private修饰的成员变量或者方法只能在本类中进行直接访问。
封装的步骤:
1) 使用private修饰需要被封装的属性。
2) 提供一个公共的方法设置或者获取该私有的成员属性。
命名规范:
set属性名();
get属性名();
注意: 如果比较两个字符串的内容是否一致,不要使用==比较, 使用equals方法。
规范 : 在现实开发中一般实体类的所有成员属性(成员变量)都要封装起来。
实体类:实体类就是用于描述一类 事物的就称作为实体类。
封装的好处:1)提高数据的安全性。
2)操作简单。
3)隐藏了实现。
29. 构造函数的作用: 给对应的对象进行初始化。
构造函数的定义的格式:修饰符 函数名(形式参数){
函数体...
}
构造函数要注意的细节:1)构造函数是没有返回值类型的。
2)构造函数的函数名必须要与类名一致。
3)构造函数并不是由我们手动调用的,而是在创建对应的对象时,jvm就会主动调用到对应的构造函数。
4)如果一个类没有显式的写上一个构造方法时,那么java编译器会为该类添加一个无参的构造函数的。
5)如果一个类已经显式的写上一个构造方法时,那么java编译器则 不会再为该类添加一个无参的构造方法。
6)构造函数是可以在一个类中以函数重载 的形式存在多个的。
注意:java编译器添加 的无参构造方法的权限修饰符与类的权限修饰是一致的。
构造函数与普通 函数的区别:
1) 返回值类型的区别:
1. 构造函数是没有返回值类型 的,
2. 普通函数是有返回值类型的,即使函数没有返回值,返回值类型也要写上void。
2) 函数名的区别:
1. 构造函数的函数名必须要与类名一致,
2. 普通函数的函数名只要符合标识符的命名规则即可。
3) 调用方式的区别:
1. 构造函数是 在创建对象的时候由jvm调用的。
2. 普通函数是由我们使用对象调用的,一个对象可以对象多次普通 的函数,
4) 作用上的区别:
1. 构造函数 的作用用于初始化一个对象。
2. 普通函数是用于描述一类事物的公共行为的。
30. 构造代码块:
构造代码块的作用:给对象进行统一的初始化。
构造代码块的格式:{
构造代码块
}
注意:1) 构造代码块的大括号必须位于成员位置上。2) 编译时构造代码块比构造函数先运行。
代码块的类别:1) 构造代码块。
2) 局部代码块. 大括号位于方法之内。 作用:缩短局部 变量 的生命周期,节省一点点内存。
3) 静态代码块 static
构造 代码块要注意的事项:
1) java编译器编译一个java源文件的时候,会把成员变量的声明语句提前至一个类的最前端。
2) 成员变量的初始化工作其实都在在构造函数中执行的。
3) 一旦经过java编译器编译后,那么构造代码块的代码块就会被移动构造函数中执行,是在构造函数之前执行的,构造函数的中代码是最后执行的。
4) 成员变量的显示初始化与构造代码块的代码是按照当前代码的顺序执行的。
如下所示:最后结果是300000000
//构造函数 public Demo5(){ //构造函数 i = 300000000; } //构造代码块 //构造代码块的初始化 { i = 200000000; } int i = 100000000; //成员变量的显初始化31. this关键字:
this关键字代表了所属函数的调用者对象。
this关键字作用:1) 如果存在同名成员变量与局部变量时,在方法内部默认是访问局部变量的数据,可以通过this关键字指定访问成员变量的数据。
2) 在一个构造函数中可以调用另外一个构造函数初始化对象。如:this();调用本类无参构造函数。this(name);调用本类一个参数的构造函数。
this关键字调用其他的构造函数要注意的事项:1) this关键字调用其他的构造函数时,this关键字必须要位于构造函数中的第一个语句。
2) this关键字在构造函数中不能出现相互调用的情况,因为是一个死循环。
this关键字要注意事项:1) 存在同名的成员变量与局部变量时,在方法的内部访问的是局部变量(java 采取的是“就近原则”的机制访问的)
2) 如果在一个方法中访问了一个变量,该变量只存在成员变量的情况下,那么java编译器会在该变量的前面添加this关键字。
注意:一个方法要运行的时候,jvm会在栈内存中开辟一片属于这个方法的空间,让这个方法在这片空间内执行。
32. static:
静态的成员变量只会在数据共享区中维护一份,而非静态成员变量的数据会在每个对象中都维护一份的。
static修饰成员变量 :如果有数据需要被共享给所有对象使用时,那么就可以使用static修饰。即:static修饰成员变量时,那么该成员变量的数据就是一个共享的数据.。静态成员变量的访问方式:
方式1: 可以使用对象进行访问。
格式: 对象.变量名。
方式二: 可以使用类名进行访问。
格式: 类名.变量名;
注意:1)非静态的成员变量只能使用对象进行访问,不能使用类名进行访问。
2)千万不要为了方便访问数据而使用static修饰成员变量,只有成员变量的数据是真正需要被共享的时候才使用static修饰。
static修饰方法(静态的成员方法):
访问方式:
方式一:可以使用对象进行访问。
对象.静态的函数名();
方式二:可以使用类名进行访问。
类名.静态函数名字。
推荐使用是类名直接访问静态的成员。
静态的成员变量与非静态的成员变量的区别:1) 作用上的区别:
(1) 静态的成员变量的作用共享一个 数据给所有的对象使用。
(2)非 静态的成员变量的作用是描述一类事物的公共属性。
2) 数量与存储位置上的区别:
(1)静态成员变量是存储方法 区内存中,而且只会存在一份数据。
(2)非静态的成员变量是存储在堆内存中,有n个对象就有n份数据。
3) 生命周期的区别:
(1) 静态的成员变量数据是随着类的加载而存在,随着类文件的消失而消失。
(2)非静态的成员数据是随着对象的创建而存在,随着 对象被垃圾回收器回收而消失。
静态函数要注意的事项:1) 静态函数是可以调用类名或者对象进行调用的,而非静态函数只能使用对象进行调用。
2) 静态的函数可以直接访问静态的成员,但是不能直接访问非静态的成员。
原因:静态函数是可以使用类名直接调用的,这时候可能还没有存在对象,而非静态的 成员数据是随着对象 的存在而存在的。
3) 非静态的函数是可以直接访问静态与非静态的成员。
原因:非静态函数只能由对象调用,当对象存在的时候,静态数据老早就已经存在了,而非静态数据也随着对象的创建而存在了。
4) 静态函数不能出现this或者super关键字。
原因:因为静态的函数是可以使用类名调用的,一旦使用类名调用这时候不存在对象,而this关键字是代表了一个函数 的调用者对象,这时候产生了冲突。
静态的数据的生命周期:静态的成员变量数据是优先于对象存在的。
33. main函数的详解:
public : 公共的。 权限是最大,在任何情况下都可以访问。
原因: 为了保证让jvm在任何情况下都可以访问到main方法。
static: 静态。静态可以让jvm调用main函数的时候更加的方便。不需要通过对象调用。
void: 没有返回值。 因为返回的数据是 给 jvm,而jvm使用这个数据是没有意义的。所以就不要了。
main: 函数名。 注意: main并不是关键字,只不过是jvm能识别的一个特殊的函数名而已。
arguments :担心某些程序在启动需要参数。
34. 单例设计模式:保证一个类在内存中只有一个对象。
单例设计模式的步骤:
饿汉单例设计模式
1) 私有化构造函数。
2) 声明本类的引用类型变量,并且使用该变量指向本类对象。
3) 提供一个公共静态的方法获取本类的对象。
懒汉单例设计模式:1) 私有化构造函数。
2) 声明本类的引用类型变量,但是不要创建对象,
3) 提供公共静态 的方法获取本类 的对象,获取之前先判断是否已经创建了本类 对象,如果已经创建了,那么直接返回对象即可,如果还没有创建,那么先创建本类的对象,然后再返回。
例如:
//饿汉单例设计模式 ----> 保证Single在在内存中只有一个对象。 class Single{ //声明本类的引用类型变量,并且使用该变量指向本类对象 private static Single s=new Single(); //私有化构造函数 private Single() {} //提供一个公共静态的方法获取本类的对象 public static Single getInstance() { return s; } } //懒汉单例设计模式 class Single2{ //声明本类的引用类型变量,不创建本类的对象 private static Single2 s; //私有化构造函数 private Single2() {} public static Single2 getInstance() { if(s==null) { s=new Single2(); } return s; } }
推荐使用: 饿汉单例设计模式。 因为懒汉单例设计模式会存在线程安全问题,目前还不能保证一个类在内存中只有一个对象。