学习
Java
示例及笔记,部分资料来源于网络,整理过来仅供参考使用。推荐新手参考 Java 教程 来学习。
Java
是由 Sun Microsystems
公司于1995年5月推出的 Java
面向对象程序设计语言和 Java
平台的总称。由 James Gosling
和同事们共同研发,并在1995年正式推出。
Java分为三个体系:
- JavaSE(J2SE):
Java2 Platform Standard Edition
JAVA平台标准版 - JavaEE(J2EE):
Java 2 Platform,Enterprise Edition
JAVA平台企业版 - JavaME(J2ME):
Java 2 Platform Micro Edition
JAVA平台微型版
2005年6月,JavaOne
大会召开,SUN
公司公开 Java SE 6
。此时,Java
的各种版本已经更名以取消其中的数字"2":J2EE
更名为 Java EE
,J2SE
更名为 Java SE
,J2ME
更名为Java ME
。
2009年04月20日,甲骨文(Oracle
) 74亿美元收购 Sun
,取得 Java
的版权。
2014年3月18日,Oracle
发布 Java SE 8
。
受限于篇幅,这里不对开发环境配置做更多的说明,请参考以下链接:
- Java 开发环境配置
- Mac环境下配置Java开发环境(jdk maven tomcat idea)
- Ubuntu下maven安装和tomcat简易安装
- Ubuntu下安装jdk和maven并配置相关环境变量
编写 HelloWorld.java
代码,示例代码位于 examples/src/main/java/com/raoyc/demo/HelloWorld.java
。
package com.raoyc.demo;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
运行,如果你使用 诸如 Virtual Studio Code
(搭配 JAVA
相关扩展插件) 、 IDEA
与 Eclipse
等集成环境(可能需要进行某些配置),可以很方便在源代码文件(右键)点击运行,得到结果。
你也可以手动编译运行源码文件,操作如下:
mkdir classes
javac examples/src/main/java/com/raoyc/demo/HelloWorld.java -d ./classes
java -classpath ./classes com.raoyc.demo.HelloWorld
Hello Wolrd!
编写Java程序时,应注意以下几点:
- 大小写敏感:
Java
是大小写敏感的,这就意味着标识符Hello
与hello
是不同的。 - 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如
MyFirstJavaClass
。 - 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记
Java
是大小写敏感的),文件名的后缀为.java
。(如果文件名和类名不相同则会导致编译错误)。 - 主方法入口:所有的
Java
程序由public static void main(String []args)
方法开始执行。
更多参考: Java 基础语法 。
整型:
byte(字节型)
short(短整型)
int(整型)
long(长整型)
浮点型:
float(单精度浮点型)
double(双精度浮点型)
布尔型:
boolean(布尔型)(它只有两个值可取 true false)
字符型:
char(字符型)
类型转换等请参考:Java 基本数据类型
对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
类:类是一个模板,它描述一类对象的行为和状态。
示例代码 DogTest
当在一个源文件中定义多个类,并且还有 import
语句和 package
语句时,要特别注意这些规则。
- 一个源文件中只能有一个
public
类 - 一个源文件可以有多个非
public
类 - 源文件的名称应该和
public
类的类名保持一致。例如:源文件中public
类的类名是Employee
,那么源文件应该命名为Employee.java
。 - 如果一个类定义在某个包中,那么
package
语句应该在源文件的首行。 - 如果源文件包含
import
语句,那么应该放在package
语句和类定义之间。如果没有package
语句,那么import
语句应该在源文件中最前面。 import
语句和package
语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。- 类有若干种访问级别,并且类也分不同的类型:抽象类和
final
类等。
除了上面提到的几种类型,Java
还有一些特殊的类,如:内部类、匿名类。
public class Variable {
int a, b, c; // 申明3个int型变量 a b c
int d = 3, e = 4, f = 5; // 申明3个int型变量 d e f 并赋值
byte z = 22;
// string 必须使用双引号
String s = "hello world"; // 实例变量
static Float PI = 3.14f; // 类变量
// char 必须使用单引号
char x = 'x';
char dao = '道';
char uDao = '\u9053'; // unicode 编码的 '道'
public void method() {
int i = 0; // 局部变量
}
}
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
- 访问修饰符不能用于局部变量;
- 局部变量只在声明它的方法、构造方法或者语句块中可见;
- 局部变量是在栈上分配的;
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量;
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:
ObejectReference.VariableName
。
- 类变量也称为静态变量,在类中以
static
关键字声明,但必须在方法构造方法和语句块之外。 - 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用。常量是指声明为
public/private
,final
和static
类型的变量。常量初始化后不可改变。 - 静态变量储存在静态存储区。经常被声明为常量,很少单独使用
static
声明变量。 - 静态变量在第一次被访问时创建,在程序结束时销毁。
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为
public
类型。 - 默认值和实例变量相似。数值型变量默认值是
0
,布尔型默认值是false
,引用类型默认值是null
。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。 - 静态变量可以通过:
ClassName.VariableName
的方式访问。 - 类变量被声明为
public static final
类型时,类变量名称一般建议使用大写字母。如果静态变量不是public
和final
类型,其命名方式与实例变量以及局部变量的命名方式一致。
Java
中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
default
(即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。private
: 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。public
: 对所有类可见。使用对象:类、接口、变量、方法protected
: 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类),接口及接口的成员变量和成员方法不能声明为protected
。
访问控制规则
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N(说明) | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
protected
需要从以下两个点来分析说明:
- 子类与基类在同一包中:被声明为
protected
的变量、方法和构造器能被同一个包中的任何其他类访问; - 子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的
protected
方法,而不能访问基类实例的protected
方法。
访问控制和继承
- 父类中声明为
public
的方法在子类中也必须为public
。 - 父类中声明为
protected
的方法在子类中要么声明为protected
,要么声明为public
,不能声明为private
。 - 父类中声明为
private
的方法,不能够被继承。
为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
static
修饰符,用来修饰类方法和类变量。final
修饰符,用来修饰类、方法和变量,final
修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。abstract
修饰符,用来创建抽象类和抽象方法。synchronized
和volatile
修饰符,主要用于线程的编程。
更多查阅:http://www.runoob.com/java/java-modifier-types.html 。
运算符、循环、条件与switch/case
等知识点,类似于你所熟知的某门语言,如 javascript/php/c/c++
等语言,这里限于篇幅不过多赘述。您可以查阅最后一节提供的参考资源链接来学习相关内容。另外,也可参考本仓库的示例代码: OperatorTest 与 ControlFlowTest 。
数组是用来存储固定大小的同类型元素。
public class ArrayTest {
public static void main(String[] args) {
// 数组大小
int size = 7;
// 定义数组
String[] days = new String[size];
days[0] = "Sunday";
days[1] = "Monday";
days[2] = "Tuesday";
days[3] = "Wednesday";
days[4] = "Thursday";
days[5] = "Friday";
days[6] = "Saturday";
System.out.println("7 days in one week:");
for (String day : days) {
System.out.println(day);
}
}
}
排序算法:冒泡排序 。
向量(
Vector
)类和传统数组非常相似,但是Vector
的大小能根据需要动态的变化。和数组一样,Vector对象的元素也能通过索引访问。
import java.util.Enumeration;
import java.util.Vector;
public class VectorTest {
public static void main(String[] args) {
Vector v = new Vector(3, 2);
System.out.println("Initial size: " + v.size());
System.out.println("Initial capacity: " + v.capacity());
v.addElement(new Integer(1));
v.addElement(new Integer(2));
v.addElement(new Integer(3));
v.addElement(new Integer(4));
Enumeration vEnum = v.elements(); // 枚举
System.out.println("Elements in vector:");
while(vEnum.hasMoreElements()) {
System.out.print(vEnum.nextElement() + " ");
}
}
}
栈(
Stack
)实现了一个后进先出(LIFO
)的数据结构。你可以把栈理解为对象的垂直分布的栈,当你添加一个新元素时,就将新元素放在其他元素的顶部。当你从栈中取元素的时候,就从栈顶取一个元素。换句话说,最后进栈的元素最先被取出。
Hashtable
类提供了一种在用户定义键结构的基础上来组织数据的手段。Hashtable
是原始的java.util
的一部分, 是一个Dictionary
具体的实现 。然而,Java 2
重构的Hashtable
实现了Map
接口,因此,Hashtable
现在集成到了集合框架中。它和HashMap
类很相似,但是它支持同步。像HashMap
一样,Hashtable
在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。
import java.util.Enumeration;
import java.util.Hashtable;
public class HashtableTest {
public static void main(String[] args) {
Hashtable balance = new Hashtable();
Enumeration names;
String str;
double bal;
balance.put("Zara", new Double(3434.34));
balance.put("Mahnaz", new Double(123.22));
balance.put("Ayan", new Double(1378.00));
balance.put("Daisy", new Double(99.22));
balance.put("Qadir", new Double(-19.08));
// Show all balances in hash table.
names = balance.keys();
while (names.hasMoreElements()) {
str = (String) names.nextElement();
System.out.println(str + ": " + balance.get(str));
}
System.out.println();
// Deposit 1,000 into Zara's account
bal = ((Double) balance.get("Zara")).doubleValue();
balance.put("Zara", new Double(bal + 1000));
System.out.println("Zara's new balance: " + balance.get("Zara"));
}
}
Apache Thrift
相关介绍以及具体语言的示例请参考我的 learning_thrift 仓库。
namespace java com.raoyc.thrift.demo.service
service PingService {
string ping(),
void say(1:string msg)
}
mkdir javagen
thrift -out javagen/ --gen java ping.thrift
执行完之后可以看到 javagen
文件夹下多出含包名(com.raoyc.thrift.demo
)路径的 PingService.java
文件。
移动或复制生成的上一步文件到项目源码对应的包目录下,本示例中即为:examples/src/main/java/com/raoyc/thrift/demo/service/PingService.java
。
编写实例化 PingService.Iface
的类,本示例代码位于:examples/src/main/java/com/raoyc/thrift/demo/service/impl/PingServiceImpl.java
package com.raoyc.thrift.demo.service.impl;
import com.raoyc.thrift.demo.service.PingService;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PingServiceImpl implements PingService.Iface {
private Logger logger = LoggerFactory.getLogger(PingService.class);
@Override
public String ping() throws TException {
System.out.println("pong");
return "pong";
}
@Override
public void say(String msg) throws TException {
System.out.println(msg);
}
}
具体请参考示例代码:
使用 IDE
安装好依赖, 可以很方便的运行 ThriftServer
与 ThriftClient 代码。
运行结果大概如下:
# start ThriftServer on #terminal#1
ThreadedSelectorServer start....
# start ThriftClient on terminal#2
Client say by class com.raoyc.thrift.demo.ThriftClient@1406718218
# meanwhile on terminal#1 will display
pong
Hello from Java
Quartz
对任务调度的领域问题进行了高度的抽象,提出了调度器、任务和触发器这3个核心的概念,并在 org.quartz
通过接口和类对重要的这些核心概念进行描述。
Quartz
调度包的两个基本单元是作业和触发器。作业是能够调度的可执行任务,触发器提供了对作业的调度。
调度器:调度器用于将与作业触发器关联,一个作业可关联多个触发器,这样每个触发器被可以触发的作业执行;一个触发器可用于控制多个作业,触发触发时,全部作业将获得调度。Quartz
的调度器由 Scheduler
接口体现。
作业:只需实现 org.quartz.job
接口即可。Job
接口包含一个方法 execute()
,execute
方法体是被调度的作业体。一旦实现 Job
接口和 execute()
方法, Quartz
确定作业运作的时候,它将调用 execute()
方法体。
触发器:有SimpleTrigger
和 CronTrigger
等类型。