序言
众所周知,程序员需要快速学习新知识,所以就有了《21天精通C++》和《MySQL-从删库到跑路》这样的书籍,Java作为更“高级”的语言也不应该落后,所以我就写一个《极·Java速成教程》,让想学的人能够快速学习Java(手斜)。
本文大概分三大部分:
- 编程基础知识
- 面向对象思想
- 数据类型
- 运算符
- 流程控制
- Java语言基础
- Java高级特性
本文请逐字理解文本内容,本文仅供理解和学习Java编程,不可作为概念性参考
本文是阅读《Java编程思想》后的读后感
本文着重于理解某种思想,所以些许描述显得晦涩,意会即可
面向对象思想
何为面向对象
Java是一个从设计之初就遵循面向对象思想的语言,因此而有着诸多面向对象的特性,那么问题来了,面向对象指的是什么?
面向对象,不是指的脸超女朋友,而是说编程的时候,你所操作的一切事物都是“对象”,假如说Java程序员是个搬砖工,那Java操作的对象就是搬砖工手里的砖,一块砖就是一个对象,一堆转就是一堆对象,诸多同样的对象可以用一个概念来概括,这个概念就是“类”。
先在我们可以思考砖是个什么东西,也就是砖的“概念(类)”:砖,由土烧制而成,可以用来砌墙、铺地和垫桌角,有一定的重量和体积,能被搬被砌。仔细分析这句定义,可以发现能分为4小句:
- 砖是由土烧制而成。也就是说,一个类都是从另一个或多个类继承发展而来,也就是“继承(extend)和组合自另一个或多个类”,在Java中,所有类都继承和扩展自Object类,在自己写的程序中,一个类可以继承和扩展自官方的类,别人写的类和自己写的类。
- 砖可以用来砌墙、铺地和垫桌角。也就是同一个类可以根据不同的需求去加工处理,修改为不同的“形状”,添加不同的属性,在不同的地方起到不同的作用。
- 砖由一定的重量和体积。也就是说每个类都有其属性,但是对于同一种属性,他们的值未必相同,正如每个砖的重量和体积都可以不同。
- 砖能被搬被砌。也就是说每个类都有其功能,属性是一个类静态的描述,而功能(或者说方法)则是一个类动态的描述。
将许多个“砖”一样的对象搭配组合,堆垒到一起,就可以构建起程序的这栋房屋,实现整体的功能。
Java中类的几个特点
Java中的类有几个特点
- 单根继承,也就是说某一个类只能直接继承自另一个类,就像砖只能由土烧制而成,即土→砖,然而除了土,砖的烧制过程中还需要加其他的配料比如外面要烧上去一层琉璃,那就得在砖本身的属性以上添加一个琉璃的属性,琉璃的属性是额外的,独立无关的,但是他们组合起来实现了更多的功能。也就是说除了直接继承,还可以添加其他类到一个类中,这种方法叫通过接口(interface)进行继承。
- 访问控制。对于一个类来说,你只能看到一个类想让你看到的部分。就像一个砖,你只能看到砖的表面,不能看到它的内里,除非敲开他,但是在Java中,这是不被允许的。一个类想让你看到的部分和不想让你看到的部分由不同的关键词进行控制:
- public 对于所有对象都公开的内容
- private 只有自己可见的内容
- protected 只有自己和自己的子孙可以看到的内容
- default 只有自己的亲戚(同一个包)可以看到的内容
我们不用关心他们内部什么样子,我们只需要关心我们需要的,暴露在外面的东西,以及对象能正常工作就行。
- “像”就是“是”。对于一个类来说,如果长得像一个东西,那就可以看作是一个东西。就像儿子像父亲,父亲能干的儿子也能干一样,一块防火转是一个砖,那他也有砖的所有属性,也能被垒起来。而一个具有垒起来方法的对象看上去能垒起来,那他就能像砖一样被垒起来。
- static属性。对于一个类来说,有的属性和方法可以是static也就是静态的,这种属性和方法不是描述一个类的对象的,而是描述一个类的。就比如可以对所有的砖执行统计数量操作,对于一个砖头让他统计同类的数量是不恰当的,但是对于一堆转,让这堆砖告诉你有多少块是可行的。
- 对象生命周期管理。Java语言的使用者不用关心Java对象是怎么诞生的,怎么消亡的,只需要在需要时new一下,创建一个对象即可,使用完以后的垃圾丢到哪里,那是Java高级特性需要研究的东西。
- Java中的类之上具有包(package)的结构,包是具有层次的,如java.lang.Math就表示java下的lang包下的Math类,这个层次结构可以有好多层,一层一层深入,所以可能这个名字会很长。在使用某一个包中的某一个类的某些内容时,需要使用import进行导入,如果需要导入某个包下的全部,可以使用*通配符。,如java.lang.*。
Java编程需要关心的点
只要想好这个类和它的对象应该怎么设计,怎么正常运行即可,其他语言的包袱,甩掉即可
数据类型
一切都是对象,而根基只需要几个
当Java使用者需要一个对象时,这个对象在内存中的位置时我们不用管也没法管的。但这个对象是怎么来的,却是可以思考的。就像房子是砖垒成的,砖是由土烧成的,那土是什么构成的呢,这么追究下去,追究到最后就成了重子和轻子了,但是我们不必追求这么细,就像Java中我们知道一切对象都有Object这个“祖宗”,但是我们不需要凡事都请动这个祖宗,它有几个子女是我们常用的,也就是“基本类型”:
类型 | 大小 | 包装器 | 初始值 |
---|---|---|---|
boolean | true/false | Boolean | false |
char | 16 bit | Character | 'u0000' |
byte | 8 bit | Byte | (byte)0 |
short | 16 bit | Short | (short)0 |
int | 32 bit | Integer | 0 |
long | 64 bit | Long | 0L |
float | 32 bit | Float | 0.0f |
double | 64 bit | Double | 0.0d |
void | Void | void | |
这些基本类型的大小都与其位数n有关,最小值为-2n-1,最大值为2n-1-1,float和double遵循IEEE754标准。 | |||
除了基本类型,还有字符串String,高精度整数BigInteger和高精度浮点数BigDecimal等常见类。 |
还有一些方便的类型可以使用
String
字符串是一个常用的类型,可以用来储存一个字符序列。字符串类型在内存中是一个不可变对象,也就是说当一个String s="ABC"
字符串在内存中创建后,它就不可以被修改了,如果执行了s+="DEF"
的操作,那这个s引用实际上是指向了一个新的"ABCDEF"对象,它与原来的"ABC"对象已经没有关系了。
字符串变量的比较是不可以直接用==
判断的。==
是用来进行引用对比的运算符,而两个内容一样的字符串引用未必在内存中指向同一个对象。因此,String对象的比较要使用equals()
方法进行。
enum
enum是枚举对象,是一个有限的可以n选1的对象的集合,可以在switch
语句内使用。形如:
public enum Spiciness{
NOT,MILD,MEDIUM,HOT,FLAMING
}
枚举类型的实例都是常量,可以使用枚举类型名.枚举常量
的方法选择常量的值。它内部创建了toString()
方法,所以可以很方便地打印枚举常量的值,还提供了ordinal()
方法,可以获取某个枚举常量在枚举类型中的顺序。以及静态的 values()
方法,可以按照枚举常量的声明顺序获取由这些常量值构成的数组。
对象应当被管理
一个对象,给他个称号,就可以根据这个名字喊他做各种事,就像家里人可以喊你小名让你干活一样。但是当出了家里,可能有好多人跟你重名,这会带来困扰,因此是不被允许的,而在外面叫你的小名,这也会带来尴尬,也就是说,这个名字超出了作用域,在Java中,一个称号(或者说引用)的作用域是从这个命名的声明到所在花括号的结尾。当然如果不关心这一点也没问题,因为IDE会提醒你这里出了问题。
当一个对象有了它的称呼以后,就可以安排他做好多的事情了,无论谁喊,只要是喊到,就可以用。在作用域范围内的所有调用都可以通过这个名字实行,而你也可以再给这个对象起另一个名字,这多个名字都是指的同一个对象,当处理不当时,这会带来一些问题,比如一个喊你张三的人给你图了个花脸,别人喊你李四把你喊过来以后也会看到一个花脸。
对于一堆相同类型的对象,可以用一个容器装住他们,方便我们管理和使用,Java中提供了多种类型的容器,有最基本的数组,也就是一串连续的空间去装一样的对象,还有其他的诸如set和map之类的容器可以装,这一点可以在后面进行详细讨论。
运算符
运算符按照字面语义理解就好
运算符有其优先级,也有短路的特征。优先级就是说先乘除后加减,短路就是逻辑运算时当直接可以产生结果时就不再继续运算。
运算符有以下几个:
+。加号,数字的累加,字符串的连接,将较小类型的数字提升为int类型。
-。减号,数字相减。负号。
*。乘号,数字相乘。
/。除号,数字相除,给出结果的整数部分,直接截断小数,不会四舍五入。
%。求余,数字相除求余数。
++自增,--自减,当出现在对象前面时先运算再输出值,当出现在对象后面时先输出值再运算。
>,<,>=,<=。大于,小于,大于等于,小于等于。顾名思义。
判断相等,对于Java来说,这是容易使人困扰的一点,因为除了在判断基本类型对象是否相等时以外,仅仅为判断别名所指向的对象是否为同一个,而不关心对象的属性是否相等。如果要判断String等官方封装好的类型,就要用到equals()
方法,但是对于自己定义的类来说,如果没有重新定义equals()
方法,就会和==一样,对引用对象进行判断,而不是对对象的属性进行判断。
&&,||,!。逻辑运算符与或非,对boolean值进行判断,两边都true时&&结果为真,两边有一个为true时||结果为真,!是对boolean对象的逻辑值进行颠倒。
&,|,^,~。按位操作符,对数字类型进行按位的与,或,异或和非操作,与,或,异或是对两个对象进行操作,非是对一个对象进行操作。
<<,>>,>>>。移位操作符,就是将操作数按位进行移位,A※※B就是将A往箭头方向移B位。如果是负数,>>在左侧补1,>>>在左侧补0。
=。数字赋值,或者是给一个对象起别名,或者是将另一个别名添加到一个对象上。
+=,-=,*=,/=,&=,|=,^=,>>=,>>>=,<<=。比较类似,a※=b就是a=a※b。当>>>=byte和short时,转化成int进行处理然后截断,可能产生不正确的结果。
指数计数法:AeB代表了Ax10B,如1.39e-43f代表float的1.39x10-43。
?:。这是个三元运算符,如A?B:C就表示如果A的逻辑结果为真,就执行B,否则就执行C。
直接常量,就是直接的数,如200D,0x200。其规则是如果后面跟D表示double,F表示float,L表示long,前面跟0表示8进制数,0x表示16进制数。
操作符使用时容易出现的问题
类型转换
(A)B可以将B强制转化为A类型,如果是从较小的类型转化为较大的类型,将不会带来问题,但如果是从较大的类型转化为较小的类型,则会带来信息丢失的问题。自定义类的转换同理。
截尾和舍入
对于浮点数来说,强制转化为整形时,会舍弃小数部分,如果要获取舍入的结果,需要使用java.lang.Math中的round()
方法。
流程控制
Java是一种面向对象的语言,但其执行过程依旧时顺序的,在顺序执行的程序中,会进行一些选择分支和循环操作。
选择
Java中可以使用if-else和switch进行分支选择。
if-else
形如
if(A){
B
}else{
C
}
就是如果判断条件A为真,则执行B,否则执行C。
switch
形如
switch(A){
case 1: B;
case 2: C;break;
case 3: D;break;
case 4: E;break;
···
}
即如果判断条件A为1,则执行B然后执行C然后中断该代码块,如果判断条件为2则执行C然后中断该代码块,如果判断条件为3则执行D然后中断该代码块,等等。
循环
循环有3种形式:while,do-while和for。
while
形如
while(A){
B
}
对判断条件A进行判断,当判断条件为A时,多次执行B代码。
do-while
形如
do{
B
}while(A)
先执行一次B代码,然后对判断条件A进行判断,当判断条件A为真时,循环至花括号头部执行B代码。
for
形如
for(int i=0,j=0;i<100;i++,j++){
B
}
首先对第一个;
前面的部分执行,常见于循环控制对象进行初始化,多个对象可以使用,
进行区分,然后对;
间的循环控制条件进行判断,如果条件为真则执行下方代码块,最后对;
后的第三部分执行,比如对循环对象进行自增操作等。实例中就是先对i和j进行初始化为0,然后判断i是否小于100,如果为真则执行B代码,最后执行i自增和j自增,然后判断i是否小于100,如果为真继续循环,该代码最后将执行B代码段100次。
在编程时,循环常在数组等可迭代对象上进行。可迭代就是可以从前到后顺序走一遍。对此,Java提供了一些便利的语法方便开发。形如
容器/数组 A;
for(int i:A){
B
}
就是说对于容器或者数组A,迭代遍历一遍,i会在每次循环中引用到A中的每个对象,然后执行B代码块。假如容器/数组A中有100个对象,那B就会被执行100次。
返回
return
结束该语句所在函数,返回返回值。
返回值类型由函数定义决定,如果不匹配且无法兼容则会IDE报错。
Java的与众不同
Java的流程控制中没有goto语句,但是通过break和continue语句,实现了从深层循环中跳出的功能。通过在循环前标记label:
,然后使用break label
和continue label
,即可跳出循环到指定位置或者是跳出本次循环到指定位置。
label1:
while(true){
label2:
while(true){
continue label1;//结束本次循环,跳转到外循环继续循环
break label1://结束外层循环
}
}
感慨
Java的基本语法,与其他的语言有相似之处,也有不同之处,但编程本来就是一种实践的技能,纸上得来终觉浅,绝知代码要手撸,还是实打实的写代码才可以将知识转化为能力。以及,文章真难写。