画布 1
Java快速入门
  1. Java基础
    第一个Java程序
      代码
        Hello.java
      编译
        javac Hello.java
      运行
        java Hello
    数据类型
      基本数据类型
      引用数据类型
        数组
        类
        接口
        null
      数据类型转换
        自动转换
          数据不丢失的前提下可以自动转换
          注意：整数默认是int，有小数时默认是double
        强制转换
        例子
    运算符、表达式、语句
      跟C语言完全一样
        if, if...else, if...else if...else, switch
        while, do...while, for; break, continue
    方法
      格式
      重载
        方法名相同
        参数类型或个数不同
        返回值可以相同也可以不同
      参数
        基本数据作为参数
          方法内部对参数的修改不影响调用者
        引用数据作为参数
          方法内部修改了堆，结果会保留下来
  2. 面向对象程序设计
    类的引入
      C语言中的结构体(struct)
        类型定义
        创建结构体
        使用
      Java中的类(class)
        class定义
        创建对象
        访问属性和方法
      构造方法
        如果没实现构造方法，编译器自动加上一个无参数的空构造方法
      this关键字
      static关键字
        类属性
        类方法
      代码块
        普通代码块
        构造代码块
        静态代码块
    封装性
      权限
        private
          本类可访问
        default
          本包可访问
        protected
          本包、其他包的子类可访问
        public
          所有
      使用方法来访问属性
        setter
        getter
    继承性
      引入
        格式
        构造方法
          如果一个类没有实现构造方法，java编译器会给它定义一个空的构造方法
          实例化子类对象时，先调用父类的构造方法，再调用子类的构造方法
          super关键字
            子类的构造方法里会默认调用super()
            可以在子类构造方法中首行自己调用super()，可加参数
            super表示父类，可以用super.xxxx调用父类方法
        子类继承父类的属性和方法，也可以覆写
        final关键字
          final类不能有子类
          final方法不能被覆写
          final变量变成常量，不能被修改
      继承的限制
        看不到父亲的私房钱：私有属性不能被子类访问
        看不到父亲的绝招：私有方法不能被子类访问
        不能把祖传的招式私吞了：子类覆写的方法不能缩小权限
      抽象类
        作用：规定子类必须实现的方法，起“模板”作用
        不能实例化对象
        子类必须覆写全部抽象方法
      接口
        作用：跟抽象类相似，起“模板”作用；子类可以继承多个接口，突破“单继承”的限制
        子类必须覆写全部抽象方法
    多态性
      方法的重载与覆写
        重载overload: 定义多个同名方法，其参数类型、个数不同
        覆写override：子类里实现跟父类同样的方法
      对象的多态性
        向上转换
          Son son = new Son(); Father f = son;
          f.fun(...)只能调用被子类覆写的方法，不能调用只在子类中定义的方法
        向下转换
          Father f = new Son(); Son son = (Son)f;
          在进行对象的向下转换前，必须首先发生对象的向上转换
        instanceof: 用来判断一个对象是不是某个类的实例
    异常
      异常
        JAVA异常类
        分为Error, Exception两类
          Error
            JAVA虚拟机本身的问题，跟程序无关，程序不需要处理
          Exception
            程序本身可以处理的异常
        还可以分为
          不可查的异常(unchecked exceptions)
            RuntimeException及其子类
          可查的异常(checked exceptions)
            其他异常
        还可以分为
          运行时异常
            RuntimeException及其子类
          非运行时异常(编译异常)
            其他异常
        处理原则
          对于可查异常必须捕捉、或者声明抛出;
允许忽略不可查的RuntimeException和Error
            “运行时异常”都是“不可查异常”
              程序中可以捕获处理它，也可以不处理
            其他异常在程序中必须处理，否则连编译都过不了
        处理方法
          try...catch...finally
            try或catch块中有return或throw语句，
会先执行finally块，再返回来执行return或throw语句
          或者再次向上throws
      throws
        写在方法的声明位置，表示如果发生异常，扔给调用者处理
        对于“不可查异常”, 系统也会抛出它，写不写throws效果一样
        对于“可查异常”，必须处理；处理方法见上
      throw
        人为抛出一个异常
        throw“不可查异常”时，可以不处理它
        throw“可查异常”时，必须处理；
处理方法见上
      assert
    包及访问权限
      包
        package
          包实际上是一个文件夹(可以含有多级子目录)
          格式：package 包名称.子包名称;
例子：package a.b.c.d;
          编译命令：javac -d <dir> <file.java> (表示在<dir>目录下生成包)
          执行方法：java 包名称.子包名称.类名称
          作用：解决类的同名冲突问题
        import
          使用不同包的类时需要import
          格式：
import 包名称.子包名称.类名称; // 手工导入某个类
import 包名称.子包名称.* ; // 由JVM自动加载所需要的类
        jar
          生成：jar -cvf <file.jar> <dir>
          查看：jar -tvf <file.jar>
          解压：tar -xvf <file.jar>
        CLASSPATH
          指定编译时查找源码的目录
          指定运行时查找的“.class文件的目录”或“jar文件”
          设置方法：
export CLASSPATH=<dir1>:<dir2>:....:<file1.jar>:<file2.jar>:...
      权限
        类
          public class可以被外包访问
          class只能在本包中访问
        类成员
          private
            本类可访问
          default
            本包可访问
          protected
            本包、其他包的子类可访问
          public
            所有
    内部类
      一般内部类
      静态内部类
      匿名内部类
  3. JNI
    JAVA调用C
      Java访问C库的方法
        1. 加载C库
          System.loadLibrary
        2. 建立Java函数名到C库函数名的映射关系
          隐式建立
            类a.b.c.d.JNIDemo要调用hello函数
            C语言中要实现Java_a_b_c_d_JNIDemo_hello
            可以用工具生成头文件
              javac -d . JNIDemo.java
              javah -jni a.b.c.d.JNIDemo
          显示建立
            JNI_OnLoad
              加载C库时就会调用这个函数
            RegisterNatives
              定义一个映射数组JNINativeMethod[]
                每个数组项含3个成员
                  Java里调用的函数名
                  JNI字段描述符
                    用"["表示数组，比如"int []"表示为"[I"
                    对于类，要用全称"L包.子包.类名;"(前面有"L"，后面有";")，
比如"Ljava/lang/String;"
                    除String类外，其他的类都用Object表示，即"Ljava/lang/Object;"
                  C语言实现的本地函数
              注册这个数组
                (*env)->RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods)
          注意：C函数比Java里的声明多2个参数: (JNIEnv *env, jclass cls)
            env提供一些辅助函数，后面有例子
            cls是对Java类或实例的引用
              如果是static方法，则cls是对Java类的引用
              否则，cls是对类的实例化对象的引用
        3. 在Java程序里调用函数
      简单例子
      Java和C库传递数据
        传递基本类型数据
          直接使用、直接返回
        传递字符串 (jni.pdf P39)
        传递数组 (jni.pdf P48
    C调用JAVA (jni.pdf P97)
      步骤
        1. 创建虚拟机
        2. 获得class
        3. 实例化对象
          对于静态方法，不需要实例化对象
          也是通过调用JAVA方法实现
        4. 调用JAVA方法
          1. 获得方法ID
          2. 构造参数
          3. 调用方法
        5. 其他
          设置属性
            1. 获得属性ID
            2. 设置属性
            3. 读取属性
public class Hello {
public static void main (String args[]) {
System.out.println("Hello, world!");
}
}
使用new来分配，不需要自己释放，把变量设为null即可
int p[]=new int [10];
p = null;
int a[]=null;
a = new int[10];
int b[]=new int[10];
int c[]={1,2,3,4,5};
int a=30;
long b = a; // 自动转换，因为long的表示范围比int大
float c = 3.1
int d = (int)c; // 必须使用强制转换
byte b= 1;
short s= 3;
编译器会判断该值有无超过该变量的表示范围，如果超过就报错。
short s = 1;
s = s + 1; // 出错，因为对于byte，short的运算，为了保证精度，会自动转换为int类型
s = (short)(s + 1);
short s2 = 1;
s = s + s2; // 出错，理由同上
public static 返回值类型 方法名称 (类型 参数1, 类型 参数2, ...) ｛
程序语句;
[return 表达式];
｝
示例：
public static int add(int x, int y) {
int sum;
sum = x + y;
return sum;
}
struct Person {
char name[100];
int age;
int money;
char *(*getName)(struct Person per);
int (*getMoney)(struct Person per);
};
char *getName(struct Person per)
{
return per.name;
}
int getMoney(struct Person per)
{
return per.money;
}
struct Person per;
struct Person *p = malloc(sizeof(struct Person));
per.getName = getName;
per.getMoney = getMoney;
p->getName = getName;
p->getMoney = getMoney;
int i = per.age;
char *str = per.getName();
class 类名称 {
数据类型 属性;
...
public 返回值类型 方法名称 (参数1, 参数2, ...) {
程序语句;
[return 表达式;]
}
}
class Person {
String name;
int age;
int money;
public String getName( );
public int getMoney( );
}
Person per = null;
per = new Person( );
int i = per.age;
int m = per.getMoney( );
class Person {
String name;
int age;
int money;
public String getName( );
public int getMoney( );
// 构造方法
访问权限 类名称 (类型1 参数1, 类型2 参数2, ...) {
程序语句;
..... // 构造方法没有返回值
}
}
表示当前对象, 当前类
方法的{}就是普通代码块
class Person {
{
// 构造块
// 每实例化一个对象前，都执行；先于构造方法执行
}
}
class Person {
static {
// 静态块
// 实例化第一个对象前，执行；只执行一次
}
}
class 父类{ }
class 子类 extends 父类 { }
abstract class 类名 {
属性;
普通方法 { }
// 抽象方法
访问权限 abstract 返回值类型 方法名 (参数) ; /* 只需要声明，不需要实现 */
}
// 接口由全局常量、公共的抽象方法组成
interface 接口名称 {
全局常量;
抽象方法;
}
interface A {
public static final i = 10;
public abstract int getNumber( );
}
interface B {
public static final String name = "www.100ask.net";
public abstract int getName( );
}
class C implements A,B {
//覆写A中方法
public int getNumber () { return i; }
//覆写B中方法
public int getName () { return name; }
}
父类 父类对象 = 子类实例;
子类 子类对象 = (子类)父类实例;
try {
// 程序语句，可能发生异常
} catch (异常类型1 e) {
// 处理语句
} catch (异常类型2 e) {
// 处理语句
} catch (异常类型3 e) {
......
}
[ finally {
//一定会运行到的代码
} ]
public 返回值 方法名(参数列表……) throws 异常类 { }
public int div (int m, int n) throws Exception {
......
}
throw 异常类的实例化对象;
throw new Exception("My Error");
assert boolean表达式 ;
assert boolean表达式 : 详细信息 ;
表达式为true时，无错误；
表达式为false时，打印“详细信息”
assert x == 0;
assert x == 0 : "X is not zero";
在内的内部定义一个类
class Outer {
class Inner {
}
}
Inner被称为内部类。
好处：内部类可以直接访问外部类的私有属性
示例：
Outer o = new Outer( );
Outer.Inner i = o.new Inner( );
class Outer {
static class Inner {
}
}
用static声明的内部类就变成了外部类；
它可以访问外部类的static属性
使用示例：
Outer.Inner a = new Outer.Inner( );
interface A {
public void printInfo( );
}
class B implements A {
public void printInfo( ) {
System.out.println("Hello, world!");
}
}
public class Anony {
public static void testFunc(A a) {
a.printInfo( );
}
public static void main(String args[]) {
testFunc(new B());
testFunc(new A( ) {
public void printInfo() {
System.out.println("Hello, world!");
}
});
}
}
typedef struct {
char *name; /* Java里调用的函数名 */
char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
void *fnPtr; /* C语言实现的本地函数 */
} JNINativeMethod;
static const JNINativeMethod methods[] = {
{"hello", "(Ljava/lang/String;)Ljava/lang/String", (void *)native_hello},
};
以下函数从Java中获得一个字符串，
再返回一个字符串给Java：
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, prompt, NULL);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
printf("%s", str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
/* We assume here that the user does not type more than
* 127 characters */
scanf("%s", buf);
return (*env)->NewStringUTF(env, buf);
}
以下函数从Java中获得一个int数组，
再求和返回一个整数给Java：
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jint *carr;
jint i, sum = 0;
carr = (*env)->GetIntArrayElements(env, arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
}
for (i=0; i< (*env)->GetArrayLength(env, arr); i++) {
sum += carr[i];
}
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
return sum;
}
JavaVM* jvm;
JNIEnv* env;
jint create_vm(JavaVM** jvm, JNIEnv** env)
{
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=.";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
return JNI_CreateJavaVM(jvm, (void **)env, &args);
}
jclass cls = (*env)->FindClass(env, "Hello");
jmethodID mid = (*env)->GetMethodID(env, cls, "<init>", "()V"); // 获得构造方法
jobject obj = (*env)->NewObject(env, cls, mid); // 实例化对象
jmethodID smid = (*env)->GetStaticMethodID(env, cls, "sayhello_to", "(Ljava/lang/String;)I");
jmethodID mid = (*env)->GetMethodID(env, cls, "saygoodbye_to", "(Ljava/lang/String;)I");
jstring jstr = (*env)->NewStringUTF(env, "weidongshan@qq.com");
(*env)->CallStaticVoidMethod(env, jobj, smid, jstr);
ret = (*env)->CallIntMethod(env, jobj, mid, jstr);
jfieldID fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
jstring jstr = (*env)->NewStringUTF(env, "Bill");
(*env)->SetObjectField(env, jobj, fid, jstr);