包、JAR、JWS
- 部署应用程序的三种情况
1 本机:JAR
2 远程:Servlets
3 介于上述两者之间:Java Web Start(JWS)、RMI - .java & .class
.java文件是我们编写代码的文件,运行时需要先编译,编译完成后会生成.class文件,我们真正执行的是.class文件中的main()函数。你可以通过-d来选择编译后的文件放在哪里,并且如果没有路径文件夹,它会自动创建(IDEA会自动帮忙管理):
//编译,生成xxxx.class
%javac -d ../classes xxxx.java
//执行
%cd ../classes
%java xxxx
- JAR
为了管理这些.class文件,使用jar工具对这些类文件进行包装,生成一个JavaARchive(JAR)文件。JAR里有一个manifest.txt文件,里面说明里这些类里面哪些有main()方法。一般在本机的部署都是使用JAR来管理。
生成、启动JAR的命令行如下:
//manifest.txt里面需要这一行:“Main-Class:xxxx"
//生成JAR
%jar -cvmf manifest.txt app1.jar *.class
//启动JAR
%java -jar app1.jar
- 包
为了避免类重名,我们可以将类打包再包装成JAR。比如JavaAPI中的java.net.socket等。但是同样我们也要避免包之间的同名,我们可以将domin放到包名称前,来标注这个包是我们项目(或公司)编写的,如:com.xhpjava.projects.Chart。
包管理规则如下(与IDEA默认的管理方式不同):
编译、构建、解压带包的JAR操作命令行在下列出,JAR内部将只有.class文件以及一个META-INF文件夹,内部有MANIFEST.MF文件(内容与manifest.txt类似):
//编译包结构文件
%javac -d ../classes com/xhpjava/xxxx.java
//执行
%cd ../classes
%java com.xhpjava.xxxx
//生成JAR,只要指定com目录就可以了
%jar -cvmf manifest.txt packxxxx.jar com
//列出jar
%jar -tf packxxxx.jar
//解压jar
%jar -xf packxxxx.jar
- Java Web Start
用户可以通过网页上的某个链接来启动Java Web Start的应用程序,一旦下载后,它就能独立与浏览器来执行。即Java Web Start应用程序是通过网络来发布的。
其工作方式如下:首先客户端点击JWS的应用程序的链接(.jnlp文件);其次Web服务器发送.jnlp给客户端,客户端打开JWS的helper app读取.jnlp并请求.jar文件;最后Web发送.jar文件给客户端,客户端调用指定的main()来启动程序。
创建与部署JWS暂时跳过,等需要的时候再看。
远程部署 & RMI
RMI
RMI可以调用不同堆(机器)上的对象。
RMI的原理是通过客户端辅助设施(stub)和服务器辅助设施(skeleton),来进行通讯,使客户端成为真正服务的代理(proxy),也就是说客户端只需要提供信息,而操作服务由服务器来完成。
RMI是有风险的会抛出异常。
RMI的通信协议一般是JRMP或IIOP,前者为java到java的远程调用,后者可以服务java到其他类型的远程方法。
创建远程服务总共有下面几个步骤:
- 创建Remote的接口
这个远程接口定义了用户端可以调用的Remote方法。这个接口是一个标记性质的接口,自身没有方法,其中声明的方法都要抛出RemoteException,并且返回值是primitive主数据类型或Serializable。
public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}
- 实现Remote方法
真正执行的类,是客户端的调用对象。
//继承UnicastRemoteObject来处理远程服务对象
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
//实现Remote接口中声明的方法
public String sayHello() {
return "Server says, 'Hey'";
}
//你可以编写更多的方法,但需要在接口中声明
//声明RemoteException的无参数构造函数
public MyRemoteImpl() throws RemoteException { }
//向RMI registry注册服务,客户端靠注册名字进行查询
public static void main(String[] args) {
try {
//创建远程对象
MyRemote service = new MyRemoteImpl();
//第一个参数为注册的名称,提供给客户端查询
Naming.rebind("Remote Hello", service);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
- 用rmic产生stub和skeleton;启动RMI registry,用户从此处获得代理(获得stub对象;启动远程服务。(在终端行不通?)
%rmic MyRemoteImpl
%rmiregistry
%java MyRemoteImpl
在创建完远程服务器后,客户端需要取得stub对象来调用需要的服务,其代码如下:
public class MyRemoteClient {
public static void main (String[] args) {
new MyRemoteClient().go();
}
public void go() {
try {
//这里要做类型转换,lookup是一个静态方法,需要输入IP地址和注册名称
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/Remote Hello");
String s = service.sayHello();
System.out.println(s);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Servlets
- servlet 是完全在HTTP服务器上运行的Java程序。
- servlet 是用来处理用户交互的网页程序,例如用户提交一些表单信息给服务器,servlet就可以把特定结果在网页上进行输出。
- JSP和servlet的区别:JSP是Java Server Pages,Web服务器最终也会将JSP转化为servlet。servlet是编写具有HTML输出的类,而JSP是写出带有Java程序的网页,JSP的好处在于更容易编写。(后面需要额外学习更多JSP和servlet的知识)
EJB & jini
EJB(Enterprise JavaBeans)是更加安全、并发、具有其他功能的RMI,但是会有点笨重。
jini看不太懂之后再说QAQ。
小知识点
-
assert断言
-
静态嵌套类
是一种静态的内部类,也具有静态属性:不需要外层的实例可以直接使用。 -
存取权限和修饰符
1 public : 任何代码都可以公开存取。
2 protected : 不常用,运行不在同一个包的子类存取。
3 defalut : 默认的种类,只允许同一个包的类别进行存取。
4 private : 只有同一类的程序代码可以存取,比如Cat不能存取Dog的private部分。 -
多维数组
-
枚举(enum)
简单用法:
public enum Members { JERRY, BOBBY, PHIL };
Members ifName = Members.BOBBY;
switch (ifName) {
case JERRY: System.out.print("make it sing ");
case PHIL: System.out.print("go deep ");
case BOBBY: System.out.print("Cassidy! ");
}
还可以加入构造函数方法和变量:
public class HFJEnum {
enum Names {
JERRY("lead guitar") {
//覆盖sings方法
public String sings() {
return "plaintively";
}
},
BOBBY("rhythm guitar") {
public String sings() {
return "hoarsely";
}
},
PHIL("bass");
private String instrument;
//构造方法,需要传入instrument参数
Names(String instrument) {
this.instrument = instrument;
}
//定义可调用的方法
public String getInstrument() {
return this.instrument;
}
public String sings() {
return "occasionally";
}
}
public static void main(String[] args) {
//每个enum都有内置的values(),用在for循环中
for(Names n : Names.values()) {
System.out.print(n);
System.out.print(", instrument: " + n.getInstrument());
System.out.println(", sings: " + n.sings());
}
}
}