java 学习笔记

1: 一个 java类文件中只能有一个public 类
2: javadoc -doc encoding UTF-8 -charset UTF-8  -d doc User.java   生成User.java 的 doc文档到doc目录下
3: javac User.java  编译User.java为二进制文件  User.class(取决于User.java中的类名称,多个类生成多个class文件)
4: java User 运行User 类文件
5: 变量 只能由字母、数字、下划线、美元符号$ 组成,其中首位不能是数字。如果变量由多个单词组成,第二个单子首字母要大写。
6: 变量定义  

  1) int number; number = 2;
  2)  int number = 2;
  3)  int number1 = 1, number2 = 2, number3;
7: 
  1)不能声明同名变量:  int  number = 1; int number = 2; 错误,注意变量名可以改变赋值, int number = 1; number = 2;这样是没问题的,number=2不是声明变量,是改变变量number的值。
  2)关键字不能作为变量: int final = 3; 错误。
  3)变量名 区分大小写:  int Number = 1; int number = 2;

8: 数据类型,分为基本类型和引用类型,基本类型包括数值类型和布尔类型,引用类型包括 类、接口、数组、空类型,其中基本类型声明的时候系统直接分配内存空间,而引用类型声明的时候,系统先分配引用空间,通过实例化才能分配数据空间,例如:

MyDate today; today.day = 14; 错误。
MyDate today; today = new Date();  正确。

int 类型,在16位机器中占16位(两个字节),在32位机器中占32位(4个字节),64位机器中占64位(8个字节)。byte 1个字节,short 2个字节,long 8个字节,char 2个字节,float 4个字节,double8个字节。

基本类型存储栈内存中,引用类型往往存储在堆内存中,而静态变量、常量、类的信息存储在方法区,例如 string country = "china"; country存入栈中,字符串"china"存在堆中。

int的取值范围是:-2^31 ~ 2^31 - 1,这里32位中第一位是符号位,剩下的31位是表示数值的。
而float的组成是:1位符号位+8位指数(q)+23位底数(b),其解释出来的形式是:b^q,由于指数q是8位有符号整数,范围是-128 ~ 127,23位的底数(无符号)最大值就是2 ^ 23,算上指数的话,最大可以表达到2 ^ 23 ^ 127,但是由于计算机的运算能力限制,并不能处理到如此大的数,但是其取值范围也会比32位整数大很多。
由于float类型是一个幂计算式,所以很多时候并不能表达一个精确值,例如0.1,如果使用float在内存中会被表示为0.10000000000000001,如果进行反复计算将会导致非常大的误差。

java中小数默认为double类型,直接赋值给float报错,例如 float number = 2.4;应该改为 float number = 2.4f;

char类型:  只能是单引号,char字符是unicode字符,准确点是utf-16,因为占2个字节,一共16位。

long类型: 结尾必须带大写或小写L。

9: float 和 double类型小技巧: 

double number = .5  等于 0.5
double number = 0.5e2 等于 0.5 * 10 ** 2


10:

二进制: 满2进1
十进制: 满10进1
八进制: 满8进1, 以0开头
十六进制: 满16进1,以0X开头

1) 十进制转二进制(转8进制一样):整数除2取余,所有余数逆向排序,就是转换的二进制数,小数乘2取整,正向排序。例如 28转二进制
   28/2 等于 14 余0
   14/2 等于 7  余0
   7/2  等于 3  余1
   3/2  等于 1  余1  
   结果是  最后的值和所有余数倒序排列  11100
  
   0.625转二进制
   0.625*2 等于 1.25  取 1
   0.25*2  等于 0.5  取 0
   0.5*2  等于 1  取 1
   结果是 101

2) 二进制转十进制:乘2的幂数,例如 1101.101  =>  1*2**3 + 1*2**2 + 1*2**0 和 1*2**-1 + 1*2**-3 => 13 和 0.625 => 13.625


3) 二进制转十六进制: 整数是倒序每四位转换为1位,如果前边不够4位,补0。例如: 1011101001 => 0010 1110 1001 => 2E9,小数是正序排列,每4位转换1位,后边不够补0。 例如: 110101 => 1101 0100 => D4

4) 二进制转八进制,如上,不同的是3位变一位。


11:  类型转换 分为 自动转换和强制转换

自动转换: 同样兼容的类型,并且小类型的值赋值给大类型(比较的不是所占内存大小,而是数值类型范围大小),那么自动转换。例如: byte number = 2; int number1 = number;需要注意的是向byte = 2;会把2自动转换为byte类型,因为赋值给小于int类型的值,如果该值超过该类型范围,直接报错,如果在这个范围内,自动转换类型。float number = 1.5; float类型不适用于这个,所以报错,无法自动转换。

强制转换: 同样兼容的类型,但是大类型的值需要赋值给小类型时,需要强制转换。例如: double number = 1.5; float number1 = (float)number;

注意: 在Java里short间的计算的结果会被转换为integer。 short number1 = 5; short number2 = 5; short number = number1 + number2; 是错误的,number1+number2的结果是自动转化为int类型。所以应该改为 short number = (short) (number1 + number2);

12: 

赋值运算符: =
复合赋值运算符: +=、-=、*=、/=、%=


13:

逻辑运算符 &&、||、&、|、^(true ^ false => true,全部为true返回false,全部为false,返回false)

位运算符:

计算机内部的二进制码有三种存在方式,正码、反码、补码,其中用到最多的是补码,计算机内部就是通过补码运算的(一定要注意:不是原码,只不过非负数 原码和反码、补码都是一样的数,容易误解为原码)。计算机内部运算的是补码(极为重要,下图事例)。

1) 正数的正码、反码、补码都一样。
2) 负数的反码是除符号位之外取反。 1000 0011 的反码  1111 1100
3) 负数的补码是它的反码加一。1000 0011 的补码  1111 1101
4)
  负数的原码 等于 负数的补码 减一 再取反  
  负数的原码等于负数的补码取反加一

1)&: 按位与运算, 对应的二进制位都为1,则为1。 例如:(全是补码)
  3&2 =>(转换补码) 0000 0000 0000 0000 0000 0000 0000 0011 & 0000 0000 0000 0000 0000 0000 0000 0010 => 0000 0000 0000 0000 0000 0000 0000 0010 => 2
  -3&2 => (先运算出-3的补码和2的补码)1111 1111 1111 1111 1111 1111 1111 1101 和 0000 0000 0000 0000 0000 0000 0000 0010 ,然后1111 1111 1111 1111 1111 1111 1111 1101 & 0000 0000 0000 0000 0000 0000 0000 0010 => 0000 0000 0000 0000 0000 0000 0000 0000 => 0

2)|: 按位或运算, 对应的二进制位其中一个为1,则为1。 例如: 
  3|2 => 0000 0000 0000 0000 0000 0000 0000 0011 | 0000 0000 0000 0000 0000 0000 0000 0010 => 0000 0000 0000 0000 0000 0000 0000 0011 => 3
  -3|2(先运算-3的补码和2的补码)1111 1111 1111 1111 1111 1111 1111 1101 和 0000 0000 0000 0000 0000 0000 0000 0010 ,然后1111 1111 1111 1111 1111 1111 1111 1101 | 0000 0000 0000 0000 0000 0000 0000 0010 => 1111 1111 1111 1111 1111 1111 1111 1111(补码) =>(补码转换为反码,-1)1111 1111 1111 1111 1111 1111 1111 1110 =>(反码转换为原码,取反)  1000 0000 0000 0000 0000 0000 0000 0001 => -1

3) ^: 按位异或运算, 对应的二进制位相异时为1,否则为0。 例如: 
  3^2 => (转换补码)0000 0000 0000 0000 0000 0000 0000 0011 ^ 0000 0000 0000 0000 0000 0000 0000 0010 => 0000 0000 0000 0000 0000 0000 0000 0001(正数补码等于原码) => 1
  -3^2 => (转换补码)1111 1111 1111 1111 1111 1111 1111 1101 和 0000 0000 0000 0000 0000 0000 0000 0010 ,然后1111 1111 1111 1111 1111 1111 1111 1101 ^ 0000 0000 0000 0000 0000 0000 0000 0010 => 1111 1111 1111 1111 1111 1111 1111 1111 (补码) =>(补码转换为反码,-1)1111 1111 1111 1111 1111 1111 1111 1110 =>(反码转换为原码,取反)  1000 0000 0000 0000 0000 0000 0000 0001 => -1

4)~: 按位非运算, 对应的二进制位全部取反,需要注意的是获取到的是补码,补码再转换成原码才是值。
   数字3非运算  ~3 => (转换补码) ~(0000 0000 0000 0000 0000 0000 0000 0011) => 1111 1111 1111 1111 1111 1111 1111 1100(补码) =>(补码转换为反码,-1)1111 1111 1111 1111 1111 1111 1111 1011(反码) =>(反码转换为原码,取反) 1000 0000 0000 0000 0000 0000 0000 0100 => -4
  
5) <<: 按位左移,向左移动位数,右边补0
   3 << 3 => (转换补码)0000 0000 0000 0000 0000 0000 0000 0011 << 3 => 0000 0000 0000 0000 0000 0000 0001 1000 => (非负数补码等于原码) => 24
   -3 << 3 => (转换补码)1111 1111 1111 1111 1111 1111 1111 1101 => 1111 1111 1111 1111 1111 1111 1110 1000(补码) => (补码转换为反码,-1)1111 1111 1111 1111 1111 1111 1110 0111(反码) =>(反码转换为原码,取反) 1000 0000 0000 0000 0000 0000 0001 1000  => -24

6) >>: 按位右移,向右移动位数,正数左边补0,负数补1
   3 >> 3 => (转换补码)0000 0000 0000 0000 0000 0000 0000 0011 >> 3 => 0000 0000 0000 0000 0000 0000 0000 0000 => (非负数补码等于原码) => 0
   -3 >> 3 => (先运算出-3的补码)1111 1111 1111 1111 1111 1111 1111 1101 => 1111 1111 1111 1111 1111 1111 1111 1111(补码) => (补码转换为反码,-1)=> 1111 1111 1111 1111 1111 1111 1111 1110(反码) =>(反码转换为原码,取反) => 1000 0000 0000 0000 0000 0000 0000 0001 => -1

7) >>>:按位右移,向右移动位数,无论正数还是负数都是补0:
   3 >>> 3 => (转换补码)0000 0000 0000 0000 0000 0000 0000 0011 >> 3 => 0000 0000 0000 0000 0000 0000 0000 0000 => (非负数补码等于原码) => 0 
   -3 >> 3 => (先运算出-3的补码)1111 1111 1111 1111 1111 1111 1111 1101 => 0001 1111 1111 1111 1111 1111 1111 1111(补码) => (非负数补码等于原码)=> 0001 1111 1111 1111 1111 1111 1111 1111 => 536870911

14: if .. else .. 两种写法,一种是有大括号,另一种没有。

1) 
int money = 600;
if(money > 500){
  System.out.println("买别墅");
}

2)
int money = 600;
if(money > 500)
  System.out.println("买别墅");

3) 注意: ruby种的 else if 可以写法也可以为 elsif
if(money == 1){
  System.out.println("1");
}else if(money == 2){
  System.out.println("2");
}else{
  System.out.println("3");
}


15:  switch(表达式)、case语句: 表达式里的值是常量,在java种的常量有byte、short、int、char,不能为long,jdk1.7以后,表达式也可以是string,jdk1.5以后,表达式也可以是enum(枚举类型)),break可以省略,但是通常是要用到的,因为去掉break后,会自动去判断下一个条件语句,default可以放到任意一个位置,一般情况放到最后面。

int jiaqi = input.nextInt();

switch(jiaqi){
  case 1:
    System.out.println("在家休息");
    break;
  case 2:
    System.out.println("在家休息");
    break;
  case 3:
    System.out.println("在周边地区玩");
    break;
  case 4:
    System.out.println("去海南");
    break;
  default:
    System.out.println("去国外玩");
}

ruby中是 case when  then else end

case jiaqi
when 1 then puts "在家休息"
when 2 then puts "在家休息"
when 3 then puts "在周边地区玩"
when 4 then puts "去海南"
else
  puts "去国外玩"
end


16:while 和 do .. while ..

do .. while ..无论while条件是否符合,先执行一次do块语句。

17:for(参数初始化;执行条件;更新循环变量): for(int i = 0; i < 10; i++){循环体;}
for的三个表达式都可以省略,执行条件省略会无限循环,参数如果在for外层初始化后,那么for语句内就可以省略,例如 i=0;for(; i < 10; i++){循环体;},封号是不可以省略的,此外for语句里可以有多个参数初始化。例如for(i = 0, j=0; i < 10; i++){循环体;}


18:  break 和 continue

break 默认中断直接包含break的块循环执行语句,如果需要终端指定的外层块语句,那么break后面需要跟标签,而标签要设置到指定的外层语句前。
continue  不中断执行语句,而是跳过continue后面的语句,继续执行循环块语句,如果需要跳转到指定的区域执行,那么需要标签,使用方法和break一样。

    int i, j;
    for(i=100; i<=200; i++){
      a:
      for(j=2; j < i; j++){
        if(i % j == 0){
          break a;
        }else if(j+1 == i){
          System.out.println(i);
        }
      }
    }


19: 数组:  引用数据类型(本质是对象,所以是引用类型),分别存入堆和栈种,堆存入具体的数据,栈存入引用对象,数组种的所有类型必须是相同数据类型,并且所有元素必须是连续存储的。

先声明后创建: int[] array; array = new int[5];
声明数组并且创建: int[] array = new int[5];
初始化:  
1) int[] array = new int[]{1,2,3,4,5};  静态初始化
2) int[] array = {1,2,3,4,5};  静态初始化,省略 new int[]。
3) int[] array = new int[3]; array[0] = 1;  动态初始化

int数组元素默认为0,boolean数组元素默认false,字符数组元素默认为'',字符串数组元素默认为null,double数组元素默认为0.0。

线性查找法: 从数组的一端开始,依次查找元素出现的位置,返回下标。
二分查找法: 针对的是有序的数组。从中间开始找。

冒泡排序、选择排序、插入排序

20: 二维数组: 引用数据类型,和一维数组一样,分别存入堆和栈中,栈存入引用对象,堆和一维数组有点区别,例如int[][] array = new int[3][];堆中先存入3个内存地址,内存地址分别指向存入具体数据的内存空间。

动态初始化:
1) int[][] array = new int[3][];
    array[0] = new int[2];
    array[1] = new int[3];
    array[2] = new int[4];
    array[0][0] = 5  或者  array[0] = new int[]{1,2,3,4};
    .....

2) int[][] array = new int[3][5];

静态初始化:
int[][] array1 = {
  {1,2,3,4,5},
  {10,20,30}
};


21: 面向对象: 封装、继承、多态

访问修饰符: public  protected  private  默认

public: 该类和非该类都可以使用
protected: 该类及其子类可以使用
private: 只允许该类可以使用,一般情况下属性都是定义为private类型加以封装
默认: 同一包中的类可以调用


构造方法: 负责对象的初始化工作,当类里没有声明构造方法时,系统会生成一个默认的无参构造方法,同一个类中可以定义多个构造方法,构造方法定义规则是public 类名(){...},没有返回类型,例如:

public class User{

  public User(){
    ...
  }

}

this关键字: 当前对象的引用,this关键字可以处理方法种形参和变量名一样的问题,当在方法内需要用到调用该方法的对象时,就可以使用this。

  private String name;
  private int age;
  private String city = "shang hai";

  public User(String name, int age, String city){
    name = name;
    age = age;
    city = city;
  }
以上构造方法的参数赋值是无效的,应该加上this改为

  private String name;
  private int age;
  private String city = "shang hai";

  public User(String name, int age, String city){
    this.name = name;
    this.age = age;
    this.city = city;
  }

在同一个类中,一个方法,调用另一个方法,this关键字可以省略,如果在同类中构造方法中调用其他构造方法,直接使用this(),并且只能放在第一个位置。

  public User(){
    System.out.println("........");
  }

  public User(String name, int age, String city){
    this(); // 放在方法顶端
    this.name = name;
    this.age = age;
    this.city = city;
  }



22: static: 修饰类的成员,静态修饰成员被所有对象共享,修饰成员变量称之为类变量,修饰成员方法称之为类方法,还可以修饰静态代码块,先于构造方法之前执行,主要用来初始化静态变量。

static{
  ...
}

代码块:先于构造方法执行,在创建实例的时候执行,每次创建实例,每次都执行。
{
  ....
}

注意: 静态方法种不能调用实例变量,不能调用this对象,因为静态方法种没有实例对象。实例方法中即可以调用实例变量也可以调用静态变量(实例方法和类方法也可以)。静态变量不属于任何一个对象,所有对象共享。


23: 单例模式:


class User{

  private static User user = null;

  private User(){
    System.out.println("b");
  }

  public static User shilihua(){
    if(user == null){
      user = new User();
    }
    return user;
  }


}


24: 重载: 方法名相同,参数名不同,跟返回类型无关,例如;

toString(){...}
toString(String str){...}


25: 包: 打包语句必须作为java程序的第一条语句,为了保障java包的名称的唯一性,要求程序员在自己包的名称前加上唯一前缀。一个类可以使用同一包中的所有类,一起其他包中的所有公开类。

package com.abc.ef;

public class User{
  ...
}

两种方式调用其他包种的类

1) java.util.Date today = new java.util.Date();
2) import java.util.Date;
    Date today = new Date();


运行编译java文件: javac -d 目标路径  java文件,javac -d . UserDemo.java


1) package com.itzhiwei;

public class User{

  private int age;

  public void setAge(int age){
    this.age = age;
  }

  public int getAge(){
    return age;
  }

}


2) import com.itzhiwei.User;

public class UserDemo{
  public static void main(String[] args){
    User user = new User();
    user.setAge(10);
    System.out.println(user.getAge());
  }
}

或者

public class UserDemo{
  public static void main(String[] args){
    com.itzhiwei.User user = new com.itzhiwei.User();
    user.setAge(10);
    System.out.println(user.getAge());
  }
}

或者

2) package com.itzhiwei;

public class UserDemo{
  public static void main(String[] args){
    User user = new User();
    user.setAge(10);
    System.out.println(user.getAge());
  }
}

将UserDemo和User放在同一包下,这样就不需要引用,而可以直接使用了。



26:  继承(is-a)、组合(has-a)、接口(like-a)


继承的特点: 代码重用、继承父类的字段和方法、

继承: 使用extends继承,super调用父类中的变量和方法,this调用当前类中的变量和方法,子类构造语句的第一条语句是调用父类的构造语句,如果是无参构造器可以省略,不写调用默认构造方法。

public class JavaTeacher extends Teacher{
  public JavaTeacher(String name, String school){
    super(name, school);
  }
}


27: 重写 相同的返回类型,相同的方法名称,相同的参数,重写的方法的访问修饰符权限不能小于被重写的方法的访问修饰符,父类中的私有方法不能被重写,不过需要注意的是父类和子类中都可以写同样名称的方法,看起来像重写,但实质上不是。完全没关系。

28: final  可以修饰变量、方法、类、引用变量(对象),修饰变量代表该变量不能被重新赋值,也就是常量了,修饰方法代表该方法不能被重写,修饰类代表该类不能被继承,修饰的引用变量(对象)表示该对象不可以指向其他的内存地址,final修饰的变量一般都是常量,而且一般都和static一起用。

final Tacher teacher = new Teacher(); teacher = new Teacher();这个就是错误的。


29: Java中的任何类都默认继承了Object类,Object类里最常用的方法是equals和toString。

class Student{...} 等同于 class Student extends Object{...}

对象.equals(对象2) 是指对象和对象2的引用地址是否相同,而字符串.equals(字符串2)是指字符串和字符串2的值是否相等,字符串 == (字符串2)是指字符串和字符串2引用地址是否相等。


30: 多态:

1)需要存在继承和实现关系
2)重写方法
3)父类或接口的引用变量可以引用子类对象。Animal animal = new Dog();

多态通过分离做什么和怎么做,从另一个角度将接口和实现分离,增加可维护性和可扩展性。



public class AnimalDemo{

  public static void main(String[] args){
    Animal an1 = new Dog("旺财");
    an1.eat();
    Animal cat = new Cat("招财猫");
    cat.eat();
  }

}


class Animal{

  private String name;

  public Animal(String name){
    this.name = name;
  }

  public void eat(){

  }
}

class Dog extends Animal{
  public Dog(String name){
    super(name);
  }

  public void eat(){
    System.out.println("啃骨头");
  }
}

class Cat extends Animal{
  public Cat(String name){
    super(name);
  }

  public void eat(){
    System.out.println("吃鱼肉");
  }
}


对象上下转型: 由子类转型成父类,称为向上转型,子类特有的方法会丢失(注意),也就是说父类的引用变量只能调用父类中有的方法和子类重写父类的方法。与之相反的操作是向下转型,不安全,可能需要instanceof操作符协助。父类引用可以指向子类对象,子类引用不能指向父类对象,上例中改为 Dog dog = new Animal("狗")是错误的,但是可以改为Animal animal = new Dog("狗");(向上转型) Dog dog = (Dog)animal;(向下转型)详细参考:http://www.cnblogs.com/fickleness/archive/2013/06/21/3149011.html

Animal animal1 = new Dog("狗"); Animal animal2 = new Cat("猫"); Dog dog = (Dog) animal2;这种就是向下转型所说的不安全,Dog实例指向了Cat,这里就用到了instanceof if(animal2 instanceof Dog){Dog dog = (Dog) animal2;}就不会报错了

instance: dog instanceof Animal  dog实例是否属于Animal类或其父类

静态绑定: static、final、private、构造方法,在程序执行前已经被绑定,在编译期执行。
动态绑定: 运行时,根据变量,对象决定调用哪个方法,


31: 方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数


32:抽象方法: 只有方法头没有方法体的方法称之为抽象方法。用abstract来定义抽象方法,抽象方法不能被调用。

使用了关键词abstract定义的类叫做抽象类,抽象方法必须在抽象类中。

继承抽象类的类要么实现抽象类的方法,要么继续抽象下去。

对象上下转型可以使用抽象类,例如

abastract class Employee{..}
class Teacher extends Employee{}
Employee teacher = new Teacher() 正确
Employee teacher = new Employee() 错误


33: interface 接口名称

接口中只能有静态常量和抽象方法。一个类可以继承一个父类但是可以实现(implements)多个接口。接口与接口之间可以通过extends来实现继承关系。

注意: 接口中定义了 int age = 10;这样的变量也会默认为 public static final int age = 10;void show();这样的方法也会默认为 public abstract void show();


抽象类和接口的关系:
抽象类和具体实现类之间是一种继承关系,父类和子类在概念上是相同的。
接口和实现类在概念上不要求相同,接口只是抽取相互之间没有关系的类的共同特征,而不去关注类的关系。它可以使没有层次关系的类具有相同的行为。

抽象类是对一组拥有相同属性和行为的逻辑上有关系的事物的抽象。接口是对一组拥有相同属性和行为的逻辑上没有关系的事物的抽象。

接口的引用变量可以指向实现它的类的对象。

public class InterfaceDemo{
  public static void main(String[] args){
    Person p = new Person();
    Child child = new Child();
    Dog dog = new Dog();
    p.feed(child);
    p.feed(dog);
  }
}


class Person{
  public void feed(Child child){
    child.eat();
  }

  public void feed(Dog dog){
    dog.eat();
  }
}

class Child{
  public void eat(){
    System.out.println("吃米饭");
  }
}

class Dog{
  public void eat(){
    System.out.println("吃骨头");

  }
}

使用接口可以改成如下,由于接口的引用变量像父类的引用变量可以指向实现他的类的对象,所以可以避免重载的问题。

public class InterfaceDemo{
  public static void main(String[] args){
    Person p = new Person();
    Child child = new Child();
    Dog dog = new Dog();
    p.feed(child);
    p.feed(dog);
  }
}

interface IAbility{
  public abstract void eat();
}

class Person{
  public void feed(IAbility iability){
    iability.eat();
  }
}

class Child implements IAbility{
  public void eat(){
    System.out.println("吃米饭");
  }
}

class Dog implements IAbility{
  public void eat(){
    System.out.println("吃骨头");

  }
}


34:   内部类

1) 内部类可以很好的实现隐藏,对于外部类来说内部类是它的成员,可以使用public、protected、默认 和 private 访问修饰符,其他类不可以访问外部类的 private 的内部类,默认内部类只能在同一包中访问,而public的内部类则其他包中的类也可以访问。
2) 内部类可以直接访问外部类的成员(私有成员)。
3) 外部类不能直接访问内部类的成员,必须要先建立内部类的对象。
4)  内部类可以间接的实现多继承,可以避免修改接口来实现同一个类中多个同名方法的调用。
5)  内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类(private 内部类)或者不允许其他包中的类访问外部类的内部类。
6) 内部类访问外部类实例方法和实例属性要使用 外部类名.this.属性 和 外部类名.this.方法或者直接属性和方法,访问外部类的类属性和类方法使用  外部类名.this.属性 和 外部类名.this.方法 或者 外部类.类属性和外部类.类方法。或者 直接 属性和方法。
7)  在其他类中创建外部类中内部类的实例要使用 外部类.内部类 对象 = 外部类实例名.new 内部类(参数);在外部类中创建内部类实例可以直接使用内部类创建就行,内部类 对象 = new 内部类(参数);
8) 内部类和外部类不能重名
9) 内部类不能使用static 变量和static方法,因为内部类成员必须通过实例来访问,如果要使用static变量和static方法就定义在外部类中,此外内部类可以定义 static final 这种常量。
10) 内部类的使用
public class MemberInnerClass{

  public static void main(String[] args){
    Outer1 outer1 = new Outer1();
    outer1.outerShow();
    Outer1.Inner1 inner1 = outer1.new Inner1();
    inner1.innerShow();
  }

}

class Outer1{
  private String name = "张三";
  private int num1 = 10;
  public void outerShow(){
    System.out.println(name);
    System.out.println(num1);
  }
  public class Inner1{

    private String name = "李四";
    private int num2 = 10;
    public void innerShow(){
      System.out.println(name);
      System.out.println(num2);
      Outer1.this.outerShow();  //可以写为outerShow();
    }

  }
}
11): 外部类通过内部类实现多继承

public class MultiExtendsDemo{
  public static void main(String[] args){
    C c = new C();
    c.showA();
    c.showB();
  }
}

class A{
  public void showA(){
    System.out.println("A");
  }
}

class B{
  public void showB(){
    System.out.println("B");
  }
}

class C{
  private class A1 extends A{
    public void showA(){
      super.showA();
    }
  }

  private class B1 extends B{
    public void showB(){
      super.showB();
    }
  }

  public void showA(){
    new A1().showA();
  }

  public void showB(){
    new B1().showB();
  }

}

12) 继承类和实现的接口有同样名称的方法,通过内部类解决问题。

public class Demo2{
  public static void main(String[] args){
    Son son = new Son();
    son.show();
    son.show2();
  }
}

abstract class Parent{
  public abstract void show();
}

interface Ishow{
  public abstract void show();
}

class Son extends Parent{

  public void show(){
    System.out.println("抽象类中的show方法");
  }

  class Inner2 implements Ishow{
    public void show(){
      System.out.println("接口中的show方法");
    }
  }

  public void show2(){
    new Inner2().show();
  }

}



35: 静态内部类,非静态类只能通过外部类来实例化,对于其他类来说它是隐藏的,而静态内部类则没有隐藏性,也不依赖于外部类创建。

1) 使用static修饰的内部类叫做静态内部类。静态内部类和外部类没有任何关系,只是在生成类名和类定义时有影响。静态内部类可以看成是和外部类同级的类,使用方式和外部类完全一样。 外部类.内部类 实例名称 = new 外部类.内部类(参数);

2) 静态内部类不能使用外部类的非静态属性和非静态方法。

public class MemberInnerClass{

  public static void main(String[] args){
    Outer1.Inner1 inner1 = new Outer1.Inner1();
    inner1.innerShow();
    inner1.innerShow1();
  }

}

class Outer1{
  private String name = "张三";
  public void outerShow(){
    System.out.println(age);
  }
  public static class Inner1{

    public void innerShow(){
      outerShow(); 错误,静态内部类不能使用外部类的实例方法。
    }

    public void innerShow1(){
      System.out.println(name); 错误,静态内部类不能使用外部类的实例变量。
    }

  }
}

36: 静态内部类和非静态内部类的区别

1) 非静态内部类不能有静态成员,静态内部类可以有静态成员和非静态成员。
2) 内部类对于其他类是隐藏的,内部类的实例化也需要外部类实例来实例化,而静态类对于其他类没有隐藏性,它可以直接创建。
3) 非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。



37:匿名内部类是没有名称的内部类。

1) 匿名内部类不能有静态代码块。
2) 匿名内部类必须继承一个类或者实现一个接口。
3) new interface/superclass(){...}  实例化匿名类,接口或抽象类是不可以实例化的,如果实例化了,则一定要写类体,实现抽象类或接口的方法,这就是匿名类的实例化。

public class AnonymousInnerClass{
  public static void main(String[] args){
    Person p = new Person();
    Animal dog = new Animal(){ //把匿名类对象赋给抽象父类,所以dog对象只能使用抽象类中有的方法,也就是eat(),如果使用dog.show()则会报错。
      public void eat(){
        System.out.println("啃骨头");
      }
      public void show(){
        System.out.println("show 方法");
      }
    };

    p.feed(dog);

    p.feed(new Animal(){ //匿名类
        public void eat(){
          System.out.println("吃鱼肉");
        }
    });


  }
}

class Person{
  public void feed(Animal animal){
    animal.eat();
  }
}

abstract class Animal{
  public abstract void eat();
}


如果要调用匿名类的特有方法,则需要

    new Animal(){
      public void eat(){
        System.out.println("啃骨头");
      }
      public void show(){
        System.out.println("show 方法");
      }
    }.show();

以上实例,不用匿名类,而用普通方式:


public class AnonymousInnerClass{
  public static void main(String[] args){
    Person p = new Person();
    Animal dog = new Dog();
    p.feed(dog);
  }
}

class Person{
  public void feed(Animal animal){
    animal.eat();
  }
}

abstract class Animal{
  public abstract void eat();
}

class Dog extends Animal{
  public void eat(){
    System.out.println("啃骨头");
  }
}


38: 局部内部类  定义在代码块、方法体内的类就叫局部内部类,对外部类完全隐藏,有效范围是作用域内,所以局部类不能使用访问修饰符。局部内部类只能访问方法体或代码块内的常量(jdk1.8+可以使用变量),局部内部类可以看成是一个局部变量。


public class LocalInnerClass{
  public static void main(String[] args){
    Outer3 outer3 = new Outer3();
    outer3.showOuter();
  }
}

class Outer3{
  private String name = "张三";
  public void showOuter(){
    class Inner3{
      public void showInner(){
        System.out.println(name);
      }
    }
    Inner3 inner = new Inner3();
    inner.showInner();
  }
}


39: 自动装箱和自动拆箱

自动装箱: 

1) 用基本类型的值初始化引用类型时,自动装箱。Integer age = 10; 相当于  Integer age = new Integer(10);
2) 把基本类型赋值给引用类型,自动装箱。int age = 10; Integer age1 = age;


自动拆箱: 

1)把引用类型的值赋值给基本类型,自动拆箱。Integer age = 10; int age1 = age; 相当于 int age1 = age.intValue();
2)直接对引用类型进行运算时,自动拆箱。Integer age = 10; age + 10; 引用对象age加10的时候先拆箱。


40: 枚举类型

1)定义枚举类型: public Enum Color{RED,BLUE;},枚举就是class。
2)当jvm去加载使用枚举类的时候,会预先创建多个枚举类型的对象。public Enum Color{RED,BLUE;}加载的时候相当于如下:
public static final Color RED=new Color();
public static final Color BLUE=new Color();

3)所有枚举类型都是java.lang.Enum;的子类。
4)枚举值都是public static final 类型的,所以全部大写。
5)构造器只有在构造枚举值时才能被调用,所以构造器都是private类型的。
6)枚举类就是一个类,只是已经构造除了多个对象来供使用。

public class EnumDemo{
  public static void main(String[] args){

    Color[] colors = Color.values();
    for(Color c:colors){
      System.out.println(c); // 相当于c.toString();
    }

    Person[] persons = Person.values();
    for(Person p:persons){
      System.out.println(p); // 相当于c.toString();
    }

    System.out.println(Person.P1);

    Person p = Person.P3;

    switch(p){
      case P1:
        System.out.println(Person.P1);
        break;
      case P2:
        System.out.println(Person.P2);
        break;
      case P3:
        System.out.println(Person.P3);
        break;
    }


  }
}

// public static final Color RED = new Color();
// public static final Color BLUE = new Color();
// public static final Color YELLOW = new Colo();
enum Color{
  RED, BLUE, YELLOW;
  private Color(){
    System.out.println("构造方法");
  }
}

// public static final Person P1 = new Person("张三", 30);
// public static final Person P2 = new Person("李四", 20);
// public static final Person P3 = new Person("王五", 18);
enum Person{
  P1("张三", 30), P2("李四", 20), P3("王五", 18);

  private String name;
  private int age;
  private Person(String name, int age){
    this.name = name;
    this.age = age;
  }
  public String toString(){
    return name+"---"+age;
  }

}


41:  String、StringBuffer、StringBuilder

String 字符串常量
StringBuffer 字符串变量(线程安全),默认容量(capacity())是16
StringBuilder 字符串变量(非线程安全),默认容量(capacity())是16,这里要注意capacity()和length()的区别,capacity()指的是该对象的容量,而length()是对象的实际大小。

StringBuffer和StringBuilder创建的字符串可以编辑,而String是不可变的。每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响。

定义变量:
1) StringBuilder sb = new StringBuilder(); sb.append("apple");
2) StringBuilder sb = new StringBuilder(10); sb.append("apple");
3) StringBuilder sb = new StringBuilder("apple");


42:  Date日期类、DateFormat、SimpleDateFormat


DateFormat: 提供多种日期、日期时间格式
SimpleDateFormat类可以自定义日期、时间的格式,将日期字符串转换为日期对象,也可以将日期字符串转化为日期对象。

public string final format(Date date);  把日期对象按照日期模板转换为字符串

public Date parse(String source);  把日期字符串转换为日期对象


示例:

import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;

public class DateDemo{
  public static void main(String[] args){
    Date date = new Date();
    System.out.println("date: " + date);
    System.out.println("date.getTime(): " + date.getTime());
    // date.setTime(2571242353033L);
    // System.out.println(date);

    DateFormat df1;
    DateFormat df2;
    df1 = DateFormat.getDateInstance();
    df2 = DateFormat.getDateTimeInstance();
    System.out.println("getDateInstance: "+df1.format(date));
    System.out.println("getDateTimeInstance: "+df2.format(date));
    df1 = DateFormat.getDateInstance(DateFormat.SHORT);
    System.out.println("DateFormat.SHORT: "+df1.format(date));
    df1 = DateFormat.getDateInstance(DateFormat.MEDIUM);
    System.out.println("DateFormat.MEDIUM: "+df1.format(date));
    df1 = DateFormat.getDateInstance(DateFormat.LONG);
    System.out.println("DateFormat.LONG: "+df1.format(date));
    df1 = DateFormat.getDateInstance(DateFormat.FULL);
    System.out.println("DateFormat.FULL: "+df1.format(date));
    df1 = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.CHINA);
    System.out.println("Locale.CHINA: "+df1.format(date));

    df1 = DateFormat.getDateInstance(DateFormat.FULL, new Locale("zh", "CN"));
    System.out.println("date new Locale: "+df1.format(date));
    df2 = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, new Locale("zh", "CN"));
    System.out.println("datetime new Locale: "+df2.format(date));

    String strDate = "2014-12-21 10:11:30.345";
    Date d = null;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    try{
      d = sdf.parse(strDate);
    }catch(Exception e){

    }
    System.out.println("SimpleDateFormat#parse: " + d);
    System.out.println("SimpleDateFormat#format: " + sdf.format(d));

  }
}



43:  Calendar

import java.util.Calendar;
import java.util.Locale;
import java.util.Date;
import java.text.DateFormat;


public class CalendarDemo{
  public static void main(String[] args){
    Calendar calendar = Calendar.getInstance(Locale.CHINA);
    calendar.set(2015, 8, 20, 18, 22, 22);
    System.out.println(calendar.get(Calendar.YEAR));
    System.out.println(calendar.get(Calendar.MONTH)+1);
    System.out.println(calendar.get(Calendar.DATE));
    System.out.println(calendar.get(Calendar.HOUR));
    System.out.println(calendar.get(Calendar.MINUTE));
    System.out.println(calendar.get(Calendar.SECOND));
    System.out.println(calendar.getTimeInMillis());
  }
}


44:  随机数和Math

1) System.currentTimeMillis()  当前时间毫秒数

2) Math.random() 0到1之间的随机数

3) Random


import java.util.Random;

public class MathRandomDemo{
  public static void main(String[] args){
    System.out.println(Math.floor(10.55));
    System.out.println(Math.floor(-10.55));
    System.out.println(Math.ceil(10.55));
    System.out.println(Math.ceil(-10.55));
    System.out.println(Math.pow(2, 3));
    System.out.println(Math.round(10.6));
    System.out.println(Math.random());

    // Random random = new Random(System.currentTimeMillis());
    Random random = new Random();
    System.out.println(random.nextInt(2));
    System.out.println(random.nextBoolean());
    System.out.println(random.nextFloat());
  }
}


45: 反射:  指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。获取关于类和对象的反射信息。

1) 对象.getClass()
2) 类.class
3) Class.forName("包路径")
4) 基本数据类型  
   1> 数据类型.TYPE 
   2> 数据类型.class

package com.iotek.classtype;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;

public class ClassDemo{
  public static void main(String[] args) throws Exception{
    // Class 对象的实例化方式

    // Employee employee = new Employee();
    // Class<?> classType = employee.getClass();

    // Class<?> classType = Employee.class;

    // Class<?> classType = null;
    // try{
    //   classType = Class.forName("com.iotek.classtype.Employee");
    // }catch(Exception e){}

    // Class<?> classType = int.class;

    // Class<?> classType = Double.TYPE;

    // Class<?> classType = Double.class;


    // System.out.println(classType.getName());
    // System.out.println(classType.getSuperclass().getSuperclass().getName());


    // 创建对象,使用无参构造方法
    // Class<?> classType = Class.forName("com.iotek.classtype.Employee");
    // Employee employee = (Employee) classType.newInstance(); //默认无参构造方法

    // 创建对象,使用带参数的构造方法
    Class<?> classType = Class.forName("com.iotek.classtype.Employee");
    Constructor<?> constructor = classType.getConstructor(new Class[]{});
    Employee employee = (Employee)constructor.newInstance(new Object[]{});
    // Constructor<?> constructor = classType.getConstructor(new Class[]{String.class, int.class});
    // Employee employee = (Employee)constructor.newInstance(new Object[]{"zcy", 20});
    // System.out.println(employee);

    // 返回所有的方法
    // Method[] methods = classType.getDeclaredMethods();

    // for(Method method:methods){
    //   System.out.println(method.getModifiers() + " " + method.getReturnType() + " " + method.getName());
    // }

    // 调用public方法
    // Method method = classType.getDeclaredMethod("toString", new Class[]{});
    // System.out.println(method.getName());
    // String desc = (String) method.invoke(employee, new Object[]{});
    // System.out.println(desc);

    // 调用private方法
    // Method method = classType.getDeclaredMethod("work", new Class[]{});
    // method.setAccessible(true); // 设置该私有方法可以被访问
    // method.invoke(employee, new Object[]{});

    // 获取Class对象所指定的属性
    Field field = classType.getDeclaredField("name");
    field.setAccessible(true); // 设置该私有方法可以被访问
    field.set(employee, "李四");
    System.out.println(field.get(employee));


  }
}

class Employee{
  private String name;
  private int age;

  public Employee(){
    System.out.println("无参构造方法");
  }

  public Employee(String name, int age){
    this.name = name;
    this.age = age;
  }

  public void setName(String name){
    this.name = name;
  }

  public void setAge(int age){
    this.age = age;
  }

  public String getName(){
    return name;
  }

  public int getAge(){
    return age;
  }

  public String toString(){
    return getName()+"的年龄是"+getAge();
  }

  private void work(){
    System.out.println("工作");
  }

}


46:  泛型,多个类成员变量不同,但是逻辑相同,此时有多种解决方案,如下第三种为泛型解决方案。泛型的原理是类型的参数化,即把类型看做参数,也就是说把所有要操作的数据类型看做参数,就像方法的形式参数是运转时传递的值的占位符一样。类型变量就像参数,它提供给编译器用来类型检查的信息。泛型可以提高代码的重用性和扩展性,可以在编译的时候检查数据类型,并且所有强制转换都是自动和隐式的。

泛型总结: 泛型本质上就是通过参数化类型来实现同一份代码上操作多种数据类型,泛型编程是一种编程规范,它利用参数化类型将类型抽象画,从而实现更为灵活的复用。



1)  这种方案会产生多个类,代码重复性太高了

public class Demo1{
  public static void main(String[] args){
    MyClass1 class1 = new MyClass1("zhangsan");
    System.out.println(class1.getData());
    MyClass2 class2 = new MyClass2(10);
    System.out.println(class2.getData());
  }
}


class MyClass1{
  private String data;
  public MyClass1(String data){
    this.data = data;
  }
  public void setData(String data){
    this.data = data;
  }
  public String getData(){
    return data;
  }
}

class MyClass2{
  private int data;
  public MyClass2(int data){
    this.data = data;
  }
  public void setData(int data){
    this.data = data;
  }
  public int getData(){
    return data;
  }
}



2) 编译的时候没错,但是运行的时候可能会出错。如下:

public class Demo2{
  public static void main(String[] args){
    MyClass class1 = new MyClass("zhangsan");
    System.out.println((String)class1.getData());
    MyClass class2 = new MyClass(10);
    System.out.println((Integer)class2.getData());
    System.out.println((String)class2.getData()); // 错误
  }
}


class MyClass{
  private Object data;
  public MyClass(Object data){
    this.data = data;
  }
  public void setData(Object data){
    this.data = data;
  }
  public Object getData(){
    return data;
  }
}


3)泛型

public class GenericDemo1{
  public static void main(String[] args){
    GenClass<String> gen1 = new GenClass<String>("zhangsan");
    System.out.println(gen1.getData());
    GenClass<Integer> gen2 = new GenClass<Integer>(100);
    System.out.println(gen2.getData());
    GenClass<Student> gen4 = new GenClass<Student>(new Student("lisi"));
    GenClass<GenClass<Student>> gen3 = new GenClass<GenClass<Student>>(gen4);
    System.out.println(gen3.getData().getData());

    GenClass2<String, Integer> gen5 = new GenClass2<String, Integer>("李四", 30);
    System.out.println(gen5.getData1());
    System.out.println(gen5.getData2());
  }
}


class GenClass <T>{

  private T data;


  public GenClass(T data){
    this.data = data;
  }

  public void setData(T data){
    this.data = data;
  }

  public T getData(){
    return data;
  }

}

class GenClass2<T1, T2>{
  private T1 data1;
  private T2 data2;
  public GenClass2(T1 data1, T2 data2){
    this.data1 = data1;
    this.data2 = data2;
  }
  public T1 getData1(){
    return data1;
  }

  public T2 getData2(){
    return data2;
  }
}

class Student{
  private String name;
  public Student(String name){
    this.name = name;
  }
  public String toString(){
    return "我是:"+name;
  }
}



注意:

1>: 泛型的类型参数可以是泛型类,事例如上。

2>: 泛型类可以有多个类型参数,事例如上。

3>: 泛型类可以继承泛型类,实例如下。

4>: 泛型类可以实现接口,实例如下。

5>: 泛型类指定特定类型,class 类名<T extends 类名>{},只能是该类型及其子类,需要注意的是即使是实现接口也用extends。

6>: 泛型类实例化时给定的实际类型不同,那么这些实例也不兼容,此时如果要兼容,我们需要用到泛型通配符(?)声明泛型类的变量。

  1) ?是任意类型,无限定通配符
  2) ? extends 类型,上边界限定通配符
  3)super 通配符类型限定为某个类型或者其父类型,下边界限定通配符

7>: 泛型方法, 访问修饰符 泛型类型 返回类型 方法名(参数)

8>: 不能创建泛型数组 private T[] data = new T[10],不知道具体的类型,无法分配空间,所以不能创建。


1>:

public class GenericDemo3{
  public static void main(String[] args){
    GenericClass<Dog> dogClass = new GenericClass<Dog>();
    dogClass.setObj(new Dog());
    dogClass.getObj().eat();
    GenericClass<Cat> catClass = new GenericClass<Cat>();
    catClass.setObj(new Cat());
    catClass.getObj().eat();
    GenericClass<Animal> animalClass = new GenericClass<Animal>();


    GenericClass<? extends Animal> f1 = dogClass;
    GenericClass<?> f2 = catClass;
    GenericClass<? super Dog> f3 = animalClass;
    System.out.println(f1 == dogClass);
    System.out.println(f2 == catClass);
    System.out.println(f3 == animalClass);

    GenericClass2 gen = new GenericClass2();
    gen.println(1);
    gen.println("a");

    gen.println(new Dog());
    gen.println(new Cat());

    GenericClass2.print("哈哈");


  }
}

class GenericClass2{
  public <T> void println(T content){
    System.out.println(content);
  }

  public <T extends Animal> void println(T animal){
    animal.eat();
  }

  public static <T> void print(T content){
    System.out.println(content);
  }
}

class GenericClass<T extends Animal>{
  private T obj;

  public void setObj(T obj){
    this.obj = obj;
  }

  public T getObj(){
    return obj;
  }
}

abstract class Animal{
  public abstract void eat();
}

class Dog extends Animal{
  public void eat(){
    System.out.println("啃骨头");
  }
}

class Cat extends Animal{
  public void eat(){
    System.out.println("吃鱼肉");
  }
}

2>:

public class GenericDemo3{
  public static void main(String[] args){
    GenericClass<Dog> dogClass = new GenericClass<Dog>();
    dogClass.setObj(new Dog());
    dogClass.getObj().eat();
    GenericClass<Cat> catClass = new GenericClass<Cat>();
    catClass.setObj(new Cat());
    catClass.getObj().eat();
    GenericClass<Animal> animalClass = new GenericClass<Animal>();


    GenericClass<? extends Animal> f1 = dogClass;
    GenericClass<?> f2 = catClass;
    GenericClass<? super Dog> f3 = animalClass;
    System.out.println(f1 == dogClass);
    System.out.println(f2 == catClass);
    System.out.println(f3 == animalClass);

    GenericClass2 gen = new GenericClass2();
    gen.println(1);
    gen.println("a");

    gen.println(new Dog());
    gen.println(new Cat());

    GenericClass2.print("哈哈");


  }
}

class GenericClass2{
  public <T> void println(T content){
    System.out.println(content);
  }

  public <T extends Animal> void println(T animal){
    animal.eat();
  }

  public static <T> void print(T content){
    System.out.println(content);
  }
}

class GenericClass<T extends Animal>{
  private T obj;

  public void setObj(T obj){
    this.obj = obj;
  }

  public T getObj(){
    return obj;
  }
}

abstract class Animal{
  public abstract void eat();
}

class Dog extends Animal{
  public void eat(){
    System.out.println("啃骨头");
  }
}

class Cat extends Animal{
  public void eat(){
    System.out.println("吃鱼肉");
  }
}



47:  java异常两种处理机制

1): try-catch-finally(抛异常)
2): throw(抛异常)、throws(声明异常)

1>: finally语句块不管是否抛出异常都要执行,除非在之前执行了System.exit(0)
2>: 异常分为受查异常和非受查异常,受查异常是程序之外的异常,必须捕获,不捕获无法通过编译
3>: 自定义异常必须继承目前已有的异常


事例:

import java.util.Scanner;
import java.util.InputMismatchException;


public class ExceptionDemo1{
  public static void main(String[] args){
    System.out.println("数字");
    Scanner input = new Scanner(System.in);
    int res=0;
    try{
      int number = input.nextInt();
      res = 10 / number;
    }catch(InputMismatchException e){
      System.out.println(e.getMessage());
      e.printStackTrace();
    }catch(ArithmeticException e){
      System.out.println(e.getMessage());
      e.printStackTrace();
    }finally{
      System.out.println("结果为:"+res);
    }
  }
}



import javax.xml.xpath.XPathException;

public class ExceptionDemo1{
  public static void main(String[] args){
    Bar bar = new Bar();
    try{
      bar.enter(15);
    }catch(AgeLessThanEighteenException e){
      System.out.println("错误信息"+e.getMessage());
    }
  }
}

class AgeLessThanEighteenException extends Exception{
  private String message;
  public AgeLessThanEighteenException(String message){
    this.message = message;
  }
  public String getMessage(){
    return message;
  }

}

class Bar{
  public void enter(int age) throws AgeLessThanEighteenException{
    if(age < 18){
      throw new AgeLessThanEighteenException("年龄不合格");  // 受查异常
      // throw new XPathException("年龄不合格");  // 非受查异常
    }else{
      System.out.println("欢迎光临");
    }
  }
}


48: 





















猜你喜欢

转载自zhangcaiyanbeyond.iteye.com/blog/2312375