目录
之前学习Java整理的笔记比较乱,现在打算重新学习一遍,这篇博客用来记录一下学习过程中的知识点
不断更新中 …
Java基础知识
Java操作符
Java几乎所有的操作符都只能操作“基本类”。例外的操作符是“=”、“==”和“!=”,这些操作符能操作所有的对象。
赋值操作符 “=”
其右值可以是任何常数、变量或者表达式,但左值必须是一个明确的已命名的变量。
但是对一个对象进行赋值操作时,真正操作的是对象的引用。所以“将一个对象赋值给另一个对象”,实际上是
将“引用”从一个地方复制到另一个地方。例如将对象B复制给对象A,A = B,那么A和B都指向原本只有B对象
指向的那个对象。以后对引用A和B的操作都是对同一个堆中的对象进行操作。
算术操作符
“+”、“-”、“*”、“/”、“+=”、“-=”、“*=”、“/=”、“%”、“++”、“--”这些没什么说的。
关系操作符
“>”、“<”、“>=”、“<=”......
逻辑操作符
“&&”、“||”、“!” 能根据参数的逻辑关系生成一个布尔值。
当使用逻辑操作符时,会遇到一种短路的现象。即一旦能够明确无误的确定整个表达式的值,就不再计算表达式
余下部分了。
直接常量
直接常量后面的后缀字符标志了它的类型。若为大写或小写的L,代表long。大写或小写字母F,代表float。
大写或小写D,代表double。
按位操作符
按位与“&”、按位或“|”、按位异或“^”、按位非“~” 以及 “&=”,“|=”,“^=”。
按位操作符用来操作整数基本数据类型中的单个比特,即二进制位。按位操作符会对两个参数中对应的位执行
布尔代数运算,并最终生成一个结果。
移位操作符
左移位操作符 “<<” : 按照操作符右侧指定的位数将操作符左边的操作数向左移动(在低位补0)。
有符号右移位操作符 “>>” : 按照操作符右侧指定的位数将操作符左边的操作数向右移动。符号为正在高位插0
符号位负在高位插1
无符号右移位操作符 “>>>” : 无论正负都在高位插入0。
移位可与等号组合使用(<<=或>>=或>>>=)。此时,操作符左边的值会移动由右边的值指定的位数,再将得到的结果赋值给左边的变量。
如果对char,byte或者short类型的数值进行移位处理,那么在移位进行之前,它们会被转换为int类型,并且得到的结果也是一个int类型
的值。只有数值右端的低5位才有用。
三元操作符
表达式:boolean-exp ? value0 : value1。如果boolean-exp的结果为ture,表达式的结果为value0,否则为value1。
字符串操作符
“+” +=“”没什么说的
逗号操作符
仅仅用在for循环的控制表达式。
this关键字
class Banana { void peel(int i) {...} }
public class BananaPeel{
public static void main(String[] args) {
Banana a = new Banana();
Banana b = new Banana();
a.peel(1);
b.peel(2);
}
}
上述代码中为了能够让peel()方法知道是被a还是b调用,编辑器作了一些幕后工作。它暗自把“所操作对象的引用”作为第一个参数传递给peel()
所以上述两个方法的内部表示形式为
Banana.peel(a, 1);
Banana.peel(b, 2);
对于希望在方法内部获得对当前对象的引用,Java中有个专门的关键字:this。this关键字只能在方法内部使用,表示对“调用方法的那个对象”
的引用。如果在方法内部调用同一个类的另一个方法,就不必使用this,直接调用即可。
只有当明确指出对当前对象的引用时,才需要使用this关键字。例如,当需要返回对当前对象的引用时,可以在return中返回this。
public class Leaf{
int i = 0;
Leaf increment() {
i ++;
return this;
}
void print() {
System.out.println("i = " + i);
}
public static void main(String[] args) {
Leaf x = new Leaf();
x.increament().increament().increament().print();
}
}
/*Output:
i = 3
*/
可变参数列表
从Java5开始,Java支持一种参数写法:Java类型后面加三个点(例如String...),叫可变参数列表。向其中传入参数时,它支持传入数组,
个数不一定的同类型参数。
可变参数列表的使用规则:
1. 在调用方法的时候,如果这个方法能够和固定参数的方法匹配,可能够和可变参数的方法匹配,那么优先选择固定参数的方法。
2. 要调用的方法可以和两个可变参数匹配,则出现错误。
3. 一个方法只能有一个可变长参数,并且这个可变长参数必须是该方法的最后一个参数。
class TestMethod {
public void Variable(int... a) {
for(int i = 0; i < a.length; i ++) {
System.out.println(a[i]);
}
}
}
class Test {
public static void main(String[] args) {
TestMethod m = new TestMethod();
m.Variable();
m.Variable(10);
m.Variable(10, 20, 30, 40, 50);
}
}
Java常用工具类
Random
//Random类用于生成随机数,该类有两种构造方法
Random rnd = new Random();//无参构造,创建一个新的随机数生成器。此构造方法将随机数生成器的种子设置为某个值,该值与此构造
//方法的所有其他调用所用的值完全不同
Random rnd = new Random(100);//有参构造,使用单个long类型的种子创建一个随机数生成器。该种子是伪随机数生成器的内部状态的初始值
区别就是创建Random对象时是使用随机种子还是自己指定种子。种子是随机算法的起源数字,和生成的随机数区间没有任何关系。但是对于种子
相同的Random对象,生成的随机数序列是一样的。
Random ran1 = new Random(100);
for (int i = 0; i < 10; i++) {
System.out.print(ran1.nextInt(10) + " ");
}
Random ran2 = new Random(100);
for (int i = 0; i < 10; i++) {
System.out.print(ran2.nextInt(10) + " ");
}
运行程序后,这两个for循环生成的随机数序列都是一样的。
Random类中的常用方法:
int nextInt(): 返回一个随机数,上下限是int的最大、小值。
int nextInt(int n): 返回一个随机数,区间为[0, n)。
Scanner
Java中的Scanner类是一个用于扫描输入文本的新的实用程序,可以对字符串和基本数据类型的数据进行分析。
其中 nextInt() nextFloat() nextDouble() ......等方法就是读取对应的基本类型的数据,如果输入了不是对应的数据就会报错。
next()方法:只读取输入直到空格。该方法不能读两个由空格或符号隔开的单词。此外,next()在读取输入后将光标放在同一行中,不会换行。
nexLine()方法:读取输入包括单词之间的空格和除回车以外的所有符号,即读取一行内容。读取输入后,nextLine()将光标定位在下一行。
即nextLine();可以用作换行。
Scanner sc = new Scanner(System.in);
System.out.print("使用next()方法接收用户的输入:");
String str = sc.next();
System.out.println("用户输入的字符串为:" + str);
sc.close();
//上述代码段当输入为“你好 Java 哈哈”时,输出结果为“用户输入的字符串为:你好”
//输入的三个字符串你好、Java、哈哈使用空格分隔,却只输出了第一个词:你好
//如果在String str = sc.next();后面再加一行str += sc.next(); 输出结果为“用户输入的字符串为:你好Java”
//将上述的 sc.next() 换成 sc.nextLine()时同样的输入,输出结果为“用户输入的字符串为:你好 Java 哈哈”
因为在使用nextInt(), nextDouble, nextFloat......等方法时如果输入的数据类型不匹配会报错,所以在输入前最好使用hasNextXxx()
方法进行验证,再使用nextXxx()来读取。
hasNextInt(), hasNextDouble()......等可以配上while循环,实现验证直到输入正确,但是hasNext()和hasNextLine()配上while会
死循环。
Arrays.sort()和Collections.sort()
Arrays和Collections都是静态类。
使用Arrays的sort方法进行排序时,如果数组是基本数据类型则只能进行升序排序。若相对基本数据类型的数组进行降序排序则需要将其转换成
对应的包装类,再创建一个实现Comparator接口的比较器,利用Arrays.sort(T[] a, Comparator<? super T> c)方法进行降序排序。
public void test()
{
int scores[] = new int[]{1,2,3,89,4};
Integer newScores[] = new Integer [5];
for(int i=0;i<scores.length;i++){
newScores[i]= new Integer(scores[i]);
}
Arrays.sort(newScores,Collections.reverseOrder());//reverseOrder方法返回一个比较器,它强行逆转指定比较器的顺序。
for (Integer i:newScores)
{
System.out.println(i);
}
//如果不使用Collections.reverseOrder()方法就需要创建一个比较器,如下:
public static class MyComparator implements Comparator<Integer>
{
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
}
//然后使用Arrays.sort(newScores, new MyComparator())进行降序排序。
Collections.sort(List<T> list) 根据元素的自然顺序对指定的列表按升序进行排序。
Collections.sort(List<T> list, Comparator<? super T> c) 根据指定的比较器产生的顺序对指定的列表进行排序。
若list中的对象是已经实现了Comparable接口的可比较对象,使用Collections.sort(List<T> list)方法默认是升序排序。
若list中的对象没有实现Comparable接口为不可比较对象,使用Collections.sort(List<T> list, Comparator<? super T> c) 通过传入
比较器对象进行排序。
Comparator和Comparable
Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。实现了Comparable接口的类的对象的列表或数组可以通过
Collections.sort或Arrays.sort进行自动排序。
//Compatable接口的定义:
public interface Comparable<T> {
public int compareTo(T o);
}
//此接口只有一个方法compareTo,比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
public class Person
{
String name;
int age;
public Person(String name, int age)
{
super();
this.name = name;
this.age = age;
}
}
//要想比较Person类的对象,可以在创建Person类时,让其实现Comparable接口,如下:
public class Person implements Comparable<Person>
{
String name;
int age;
public Person(String name, int age)
{
super();
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person p)
{
return this.age-p.getAge();
}
public static void main(String[] args)
{
Person[] people=new Person[]{new Person("x", 30),new Person("y", 20)};
Arrays.sort(people); //通过Arrays.sort对Person数组进行自然排序,即按照重写的compareTo方法进行排序
}
}
Comparator是比较接口,我们如果需要控制某个类的次序,而该类本身不支持排序(该类创建时没有实现Comparable接口),那么就可以建立一
个 “该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。
//Comparator接口的定义:
public interface Comparator<T>
{
int compare(T o1, T o2);
boolean equals(Object obj);
}
//一个类实现Comparator接口时一定要重写compare函数,可以不重写equals函数。
//compare的返回值是负数则说明o1比o2小,是零则说明o1等于o2,是正数则说明o1大于o2
//如果上面的Person类在创建时没有实现Comparable接口,现在需要比较该类的大小,可以新建一个类让其实现Comparator接口,该类即是
//我们构造的比较器
public class PersonCompartor implements Comparator<Person>
{
@Override
public int compare(Person o1, Person o2)
{
return o1.getAge()-o2.getAge();
}
}
//利用PersonComparator这个比较器就可以对Person类对象进行排序:
public class Person
{
String name;
int age;
public Person(String name, int age)
{
super();
this.name = name;
this.age = age;
}
public static void main(String[] args)
{
Person[] people=new Person[]{new Person("x", 20),new Person("y", 10)};
Arrays.sort(people,new PersonCompartor());//这种方式需要传入一个比较器类的对象
}
}
Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序
可以建立一个“该类的比较器”来进行排序。Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。两种方法各有优劣,
用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不
需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且
在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。