基础语法
Hello World!
public class helloworld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
import java.util.Scanner;
public class learn {
public static void main(String[] args) {
System.out.println("Hello World!");
Scanner sc = new Scanner(System.in);
System.out.println("Enter your name: ");
String name = sc.nextLine();
System.out.println("Hello " + name);\
sc.close();
}
}
public static void main(String[] args) {
//需要设置命令行参数
int i=Integer.parseInt(args[0]);
int j=Integer.parseInt(args[1]);
System.out.println(i+" "+j);
}
注释
单行注释//
多行注释/**/
文档注释
/**
@author 作者
@date
@version 源文件版本
其他注释内容
*/
javadoc -d mydoc -author -version helloworld.java生成index.html
基础须知
-
源文件
.java
编译后生成字节码文件
.class
输入
javac helloworld.java
编译,java helloworld
运行 -
一个java源文件中可以有多个class,但是只能有一个声明为public,并且类名需要与文件名相同
-
主程序从
main()
进入 -
输出语句
System.out.println
输出并换行System.out.print
输出不换行
关键字与保留字
变量
-
整型
类型 字节数 byte 1 short 2 int 4 long 8 short a = 1; a = a - 2;// 2为int型,编译错误,需要强制类型转换 short a = 1; a = (short) (a - 2);
-
浮点型
float
double
类型 字节数 float 4 double 8 默认浮点数为
double
型,声明float变量需加f
F
-
字符型
char
2字节使用Unicode编码,可以存储一个字母,汉字,书面语字符,比如:
char a='中';
支持转义字符\
,可以直接使用Unicode值赋值与运算 -
布尔型
boolean
,取值true
false
-
类
class
,包括字符串String
public class debug { public static void main(String[] args) { int a = 1; String b = "test"; System.out.println("Hello World" + b); System.out.println('a' + b); System.out.println('a' + a + b); System.out.println(a + b); System.out.println(a + b + a); System.out.println(a + a + b + a); } } /* Hello Worldtest atest 98test 1test 1test1 2test1 */
-
接口
interface
-
数组
[]
-
StringBuffer 和 StringBuilder
String 是被 final 修饰的,他的长度是不可变的,就算调用 String 的 concat 方法,那也是把字符串拼接起来并重新创建一个对象,把拼接后的 String 的值赋给新创建的对象
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。**和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。**在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。StringBuilder和StringBuffer 之间的最大不同在于 **StringBuilder 的方法不是线程安全的(不能同步访问)。**由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
StringBuilder sb = new StringBuilder(10);
sb.append("test");
System.out.println(sb);
sb.append("!");
System.out.println(sb);
sb.insert(5, "test");
System.out.println(sb);
sb.delete(5,8);
System.out.println(sb);
在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类
StringBuffer sBuffer = new StringBuffer("摆烂基地:");
sBuffer.append("blog");
sBuffer.append(".lrdhappy");
sBuffer.append(".com");
System.out.println(sBuffer);
方法描述 |
---|
public StringBuffer append(String s) 将指定的字符串追加到此字符序列。 |
public StringBuffer reverse() 将此字符序列用其反转形式取代。 |
public delete(int start, int end) 移除此序列的子字符串中的字符。 |
public insert(int offset, int i) 将 int 参数的字符串表示形式插入此序列中。 |
insert(int offset, String str) 将 str 参数的字符串插入此序列中。 |
replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符。 |
- 类内变量为成员变量,类变量用
static
修饰,实例变量不以static
修饰 - 方法内声明变量为局部变量,除形参外需显式化
- 形参(方法,构造器中的变量)
- 方法局部变量(方法内定义)
- 代码块局部吧变量(代码块内定义)
运算符
与C++一致,其中instanceof
判断是否是类的对象
public class debug {
public static void main(String[] args) {
boolean a = "test" instanceof String;
System.out.println(a);
}
}
位运算
<<左移
>>右移
>>>无符号右移
^异或
&与
|或
!非
~取反
库函数
import java.lang.Math;
Math.random() [0,1)double型随机数
Math.sqrt()开方
import java.lang.System;
System.currentTimeMillis()获取当前时间距离1970-1-1 00:00:00的毫秒数
eclipse快捷键
Alt+/提示
//main
public static void main(String[] args) {
}
//syso
System.out.println();
修饰符
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
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 |
流程控制
与C++一致
if
if (a) {
}
else if (b) {
}
else {
}
switch
switch (表达式) {
case 1:
break;
case 2:
break;
default:
break;
}
表达式值必须为byte,short,char,int,枚举(jdk5.0),String(jdk7.0)
for
for(初始化;循环条件;迭代){//多语句用逗号分隔
循环体;
}
foreach
for(声明语句 : 表达式) { //代码句子 }
**声明语句:**声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
**表达式:**表达式是要访问的数组名,或者是返回值为数组的方法。
public class Test {
public static void main(String[] args){
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ){
System.out.print( x );
System.out.print(",");
}
System.out.print("\n");
String [] names ={"James", "Larry", "Tom", "Lacy"};
for( String name : names ) {
System.out.print( name );
System.out.print(",");
}
}
}
while
初始化;
while(循环条件){
循环体;
迭代;
}
do while
初始化;
do{
循环体;
迭代;
}while(循环条件)
break
结束本轮循环
continue
结束本次循环
return
结束整个方法
数组
声明
type var[]或type []var
java中声明数组时不能指定其元素个数
int arr[] = new int[3];
arr[0] = 2;
arr[2] = 3;
int []arr=new int[]{2,3,3}
int []arr={3,8,9}
String arr[] = { "l", "r", "d" };
引用
数组元素下标可以为整型常量或整型表达式
arr[2*i]
每个数组都有一个length属性指明长度
System.out.println(arr.length);
数组一经分配空间,元素便被初始化
元素类型 | 默认初始值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0 |
char | 0或写为’\u0000’ |
boolean | false |
引用类型 | null |
int[] arr = new int[3];
System.out.println(arr.length);
arr = new int[5];
System.out.println(arr.length + " " + arr[4]);
// 3 5 0
动态调整String数组空间大小不初始化时,数组为空,初始化不赋值时为null
String[] a = new String[3];
System.out.println(a[1]);// null
a[1] = new String();
System.out.println(a[1]);// 空
数组赋值
数组的赋值为引用,类似于C++的浅拷贝
int[] arr1, arr2;
arr1 = new int[] { 1, 1, 1, 1, 1, 1, 1, 1 };
arr2 = arr1;
arr2[0] = 2;
System.out.println(arr1[0]);
//2
int[] arr1, arr2;
arr1 = new int[] { 1, 1, 1, 1, 1, 1, 1, 1 };
arr2 = new int[arr1.length];
for (int a = 0; a < arr1.length; a++)
arr2[a] = arr1[a];
arr2[0] = 2;
System.out.println(arr1[0]);
//1
多维数组
多维数组初始化
java多维数组不必都是规则矩阵形式
int[][] arr = new int[3][2];
int[][] arr1 = new int[3][];// 可以对arr1分别初始化
arr1[0] = new int[3];
arr1[1] = new int[1];
arr1[2] = new int[2];
// int[][] arr1 = new int[3][];直接使用后续数组不合法
int[][] arr2 = new int[][] { { 1, 2, 3 }, { 1 }, { 1, 1, 1, 1, 1 } };
多维数组特殊写法
int []x,y[];
//x为一维数组,y为二维数组
Arrays工具类的使用
import java.util.Arrays;
声明 | 用法 | 功能 |
---|---|---|
boolean equals(int []a,int b[]) | Arrays.equals(arr1, arr2) | 比较数组是否相等 |
String toString(int[] a) | Arrays.toString(arr1) | 输出数组信息 |
void fill(int[] a, int val) | Arrays.fill(arr1, 2); | 将指定值覆盖数组每个位置 |
void sort(int[] a) | Arrays.sort(arr1); | 升序排序 |
void sort(int[] a, int fromIndex, int toIndex) | Arrays.sort(arr1, 0, 4); | 指定区间排序 |
int binarySearch(Object[] a, Object key) | Arrays.binarySearch(arr1, 8); | 二分查找 |
降序排序
import java.util.Collections;
Arrays.sort(arr1, Collections.reverseOrder());
//不支持基本类型(int,double,char等),如果是int型需要改成Integer,float要改成Float
枚举
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
Color myVar = Color.BLUE;
switch(myVar) {
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
}
//for迭代枚举
for (Color myVar : Color.values()) {
System.out.println(myVar);
}
values(), ordinal() 和 valueOf() 方法
enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。
values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:
- values() 返回枚举类中所有的值。
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
- valueOf()方法返回指定字符串值的枚举常量。
枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。
枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
enum Color
{
RED, GREEN, BLUE;
// 构造函数
private Color()
{
System.out.println("Constructor called for : " + this.toString());
}
public void colorInfo()
{
System.out.println("Universal Color");
}
}
public class Test
{
// 输出
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
c1.colorInfo();
}
}
Constructor called for : RED
Constructor called for : GREEN
Constructor called for : BLUE
RED
Universal Color
面向对象
语法格式
类的创建
修饰符 class 类名{
属性声明;
方法声明;
}
public class person {
int age;
String name;
public person() {
}
public person(String n, int a) {
name = n;
age = a;
System.out.println(name + " is birth");
}
public void information() {
System.out.println(name + " " + age);
}
}
对象的创建
类名 对象名=new 类名();
person test = new person("Test", 15);
生命周期
person p1=new person();//指向p1对象
person p2=p1;//指向p1对象
p1=null;//p1指向null,p2指向p1对象
p2=null;//p2指向空,p1对象成为垃圾
匿名对象
不定义对象的句柄,直接调用这个对象的方法
new person().information();
类
属性
修饰符 数据类型 属性名=初始化值;
- 权限修饰符:
private
,public
,protected
,缺省
; - 其他修饰符
static
,final
方法
修饰符 返回值类型 方法名 (参数类型 形参){
代码;
return 返回值;
}
形参为基础数据类型时,将数据值传递,形参为引用数据类型时,将地址传递
重载
重载同名方法,与返回值类型无关,只要参数个数或类型不同,可以改变返回值类型
可变个数的形参
//jdk5.0前:采用数组形参定义方法,传入多个同一类型变量
public static void test(int a,String []books);
//jdk5.0:采用可变个数形参定义方法,传入多个同一类型变量
public static void test(int a,String...books);
封装
属性声明为private,通过public方法操作
权限修饰符 | 类内 | 同一个包 | 不同包的子类 | 同一个工程 |
---|---|---|---|---|
private | √ | |||
缺省 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
构造
修饰符 类名(参数列表){
初始化语句;
}
public person(String n, int a) {
name = n;
age = a;
System.out.println(name + " is birth");
}
- 一旦显式定义了构造器,系统将不再提供默认构造器
- 父类的构造器不可被子类继承
- 默认构造器修饰符与所属类修饰符一致
this
与C++相同
public MyClass(String name){
this.name=name;
}
public MyClass(String name,int age){
this(name);
this.age=age;
}
继承
public class Student extends person {
public String school;
}
java只支持单继承和多层继承
父类可以通过强制类型转换为子类(先使用instanceof
测试对象类型)
重写
public void information() {//person
System.out.println(name + " " + age);
}
public void information() {//student
System.out.println("stu" + name + " " + age + " in " + school);
}//子类重写函数访问权限不可比覆盖方法的访问权限小
与重载区别:重写是父类与子类之间多态性的表现,重载是类内多态性的表现
super
java类中通过super调用父类中的指定操作
- super可以访问父类定义的属性
- super可以调用父类定义的成员方法
- super可以在子类构造器中调用父类的构造器,
- super追溯不仅限于直接父类
public String getinfo() {//person
return name + " " + age;
}
public String getinfo() {//student
return super.getinfo() + " in " + school;
}
子类所有的构造器默认都会访问父类中的空参数的构造器,当父类没有空参数的构造器时,子类的构造器必须通过this(参数列表)或super(参数列表)语句指定调用的本类或父类中对应的构造器,只能二选一,放在构造器的首行
this(name,age);
super(name,age);
public Student(){
super("name",14,15);
System.out.println(super.id);
this.school="家里蹲大学";
System.out.println("This is a student from "+school);
}
多态
//虚拟方法调用(多态情况下)
person e=new student();
e.getinfo();//调用student中的getinfo
- 父类引用类型变量指向子类对象(不能再访问子类添加的属性和方法)
- 子类对象可以替代父类使用
- 方法形参为父类对象,可以用子类的对象作为实参调用该方法
- 编译时看左边,运行时看右边
重载,方法的调用地址在编译时期绑定,早绑定,静态绑定,多态只有在方法调用的时候,解释运行器才确定调用的方法,晚绑定,动态绑定
JavaBean
用java编写的可重用组件,需为符合以下标准的java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有属性及对应的get,set方法
UML类图
类名 |
---|
(+,-,#)属性名:属性类型 |
(+,-,#)方法名(参数名:参数类型) |
+ public
- private
# protected
package
java源文件第一条语句,指明文件中定义的类所属的包
同一个包下,不能命名同名的接口和类,不同的包下可以
package 顶级包名.子包名;
package com.lrdhappy.test;
MVC设计模式
将程序设计分为视图模型层,控制器层,与数据模型层
- 模型层model主要处理数据
- 数据对象封装
model.bean/domain
- 数据库操作类
model.dao
- 数据库
model.db
- 数据对象封装
- 视图层 view 显示数据
- 相关工具类
view.utils
- 自定义view
view.ui
- 相关工具类
- 控制层 controller 处理业务逻辑
- 应用界面相关
controller.activity
- 存放fragment
controller.fragment
- 显示列表的适配器
controller.adapter
- 服务相关的
controller.service
- 抽取的基类
controller.base
- 应用界面相关
JDK中主要的包
- java.lang 包含java语言核心类,如String,Math,Integer,System,Thread,提供常用功能
- java.net包含执行与网络相关的操作的类和接口
- java.io包括能提供多种输入/输出功能的类.
- java.util包含一些实用的工具类,如定义系统特性,接口的集合框架类,使用与日常日历相关的函数
- java.text包含一些java格式化相关的类
- java.sql包含了java进行的JDBC数据库编程的相关类,接口
- java.awt包含了构成抽象窗口的工具集(abstract window toolkits)多个类,被用来构建和管理应用程序的图形用户界面GUI
import
import java.util.Collections;
import java.util.* //导入util包下的所有类或接口,不包含子包
- 声明在包和类的声明间
- 如果导入的类或接口是java.lang包或当前包下的,则可以省略此import语句
- 如果代码中使用不同包下同名的类,就需要使用类的全类名的方式指明调用的是哪个类
- 如果导入java.a包下的类,那么如果需使用a包下的类的话,仍然需要导入
import static
组合的使用:调用指定类或接口下的静态的属性或方法
Object类的使用
Object类是所有java类的根父类
如果在类的声明中未使用extends关键字指明其父类,则默认为java.lang.Object
public class person {
}
public class person extends Object {
}//二者等价
method(Object obj){}//可以接受任何类作为其参数
方法结构 | 描述 |
---|---|
public Object() | 构造器 |
public boolean equals(Object obj) | 对象比较 |
public int hashCode() | 取得hash码 |
public String toString() | 对象打印时调用 |
equals()与==比较
==
既可以比较基本数据类型又可以比较引用数据类型,对于基本类型比较值,对于引用数据类型比较内存地址,若equals未被重写默认也是==,通常重写equals方法比较类的相应属性是否相等
所有类都继承了Object类,都获得了equals方法,可以重写
当使用equals比较时,对类File,String,Date及包装类来说,比较内容不必考虑是否引用了同一个对象,其都重写了equals方法,比较String应该用equals方法
Object.equals(obj2);//比较是否指向同一个对象
toString()
- 在Object类中定义,返回值为String类型,返回类名及引用的地址
- 在进行String与其他数据类型连接是,自动调用toString方法
- 可以重写,String重写为了返回字符串的值
- 基本数据类型转换为String类型是调用了对应包装类的toString
Date now=new Date();
System.out.println("now=" + now);//相当于
System.out.println("now=" + now.toString());
Wrapper包装类的使用
针对八种基本数据类型定义的引用数据类型–包装类(封装类)
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
//基本数据类型包装成包装类
int i=5;
Integer t=new Integer(i);//通过构造器实现
Float f=new Float("4.56f");//通过字符串参数构造包装类对象
//获得包装类对象中包装
Boolean bObj = false;
boolean b = bObj.booleanValue();//调用包装类的.xxxValue方法
boolean b = bObj;//jdk1.5之后支持自动装箱与拆箱,但模式必须匹配
//字符串转成基本数据类型
int j= new Integer("12");//通过构造器实现
Float f=Float.parseFloat("12.1");//通过包装类的parseXxx(String s)静态方法
//基本数据类型转换成字符串
String fstr=String.valueOf(2.34f);//调用字符串重载的valueOf()方法
String inStr=5+"";
String s=t.toString();
native
- 由C/C++实现,被编译成DLL,java调用
- 是java应用与底层操作系统或硬件交换信息的接口
- 声明为**
native method
**,可以返回任何java类型包括非基本类型,同样可以异常控制
static
- 类的属性与方法不因为对象的不同而改变,则应该设置为类属性与类方法
- 类方法不需要创建变量便可以访问
- java类中,可用static修饰属性,方法,代码块 ,内部类
- 类方法只能访问类的static修饰的结构,不能访问非static修饰的结构
- 类方法中不可有super和this
- 类方法不可被重写
public static String name="这是圆";
public static String getName(){
return name;
}
public static int total=0;
Person.total=100;//无需创建对象便可访问
单例模式
//饿汉式
private static Singleton single=new Singleton();
public static Singleton getInstance(){
return single;
}
//懒汉式
public static Singleton getInstance(){
if(single==null){
single=new Singleton();
}
return single;
}
main
由于JVM需要调用main方法所以访问权限必须是public,执行main方法无需创建对象所以为static,接收String类型的数组参数,保存执行java命令时传递给所运行的类的参数
java 字节码文件 参数1 参数2
代码块
对java类或对象进行初始化
class person() {
public static int age;
static{//静态代码块
age=1;
}
}
//不可对非静态的属性初始化
//静态代码块执行应该优先于非静态代码块,随着类的加载而加载
//只执行一次
//非静态代码块可以调用静态和非静态的属性与方法
//每次创建对象都会执行,先于构造器而进行
赋值顺序
声明成员默认初始化
显式初始化,多个初始化按序执行
构造器对成员操作
通过对象.属性,对象.方法赋值
final
声明类,变量,方法时,可使用final修饰,表示最终的
- final标记的类不能被继承(System,StringBuffer)
- final标记的方法不能被子类重写(Object类的getClass())
- final标记的成员变量或局部变量为常量,名称大写,只能被赋值一次,必须在声明或构造器,代码块中显式赋值才能使用
static final全局常量
抽象类
abstract修饰的类为抽象类,修饰的方法为抽象方法
public abstract void talk();
- 含有抽象方法的类必须声明为抽象类
- 抽象类不能被实例化,可被继承
- 抽象类子类必须重写父类的抽象方法,没有重写的仍为抽象类
- abstract不能修饰变量,代码块,构造器,私有方法,静态方法,final方法,final类
模板方法设计模式
abstract class Template{
public final void getTime(){
long start=System.currnetTimeMills();
code();
long end=System.currnetTimeMills();
System.out.println("执行时间:"+(end-start));
}
public abstract void code();
}
class SubTemplate extends Template{
public void code(){
for(int i=0;i<10000;i++){
System.out.println(i);
}
}
}
接口
继承是是不是的关系,接口是能不能的关系
- 接口是抽象方法与常量值定义的集合
- 用interface定义
- 接口中所有成员变量都是默认由public static final修饰的
- 接口中所有方法都是默认由public abstract修饰的
- 没有构造器
- 采用多继承机制
- 一个类可以实现多个接口,接口也可以继承其他接口
- 实现接口的类必须提供接口中所有的方法的具体实现内容方可实例化,否则仍为抽象类
- 接口的主要用途就是被接口实现(面向接口编程)
- 接口与实现类之间存在多态性
- 接口是一种特殊的抽象类,JDK7.0及以前指包含常量和方法的定义,没有变量和方法的实现
- 如果出现接口冲突(多个接口同名方法),实现类必须覆盖同名接口
- 类和接口同名同参数方法,遵守类优先原则
public interface Runner{
int ID=1;//public static final int ID=1;
void start();//public abstract void start();
public void run();//public abstract void run();
void stop();//public abstract void stop();
}
class Person implements Runner{
public void start(){
//
}
public void run(){
//
}
public void stop(){
//
}
}
定义方式
class Subclass extends Superclass implements InterfaceA{
}
class Subclass extends Superclass implements Runner,Swimmer{
}
Image image = new ProxyImage("test_10mb.jpg");
代理模式
//Image.java
public interface Image {
void display();
}
//RealImage.java
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
//ProxyImage.java
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
//ProxyPatternDemo.java
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
JDK8.0
java8中,可以为接口添加静态方法与默认方法
- 静态方法:
static
修饰,可以通过接口直接调用静态方法,并执行方法 - 默认方法:
default
修饰,可以通过实现类对象调用
public interface Image {
public default void f(){
}
public static void f1(){
}
void display();
}
内部类
-
一个类定义在另一个类内部,则互为内部类与外部类
-
Inner class一般用于定义它的类或语句块之内,在外部引用它时必须给出完整的名称
-
Inner class名字不能与比包含它的外部类类名相同
成员内部类
static成员内部类和非static成员内部类
- 可以声明为private和protected
- 可以调用外部结构
- 可以声明为static,但就不能使用外部非static成员变量,非static的内部成员类中的成员不可以被声明为static
- 可以声明为abstract,可以被其他内部类继承
- 可以声明为final
- 外部类访问内部类的成员需要使用
内部类.成员
,内部类对象.成员
,内部类成员可以直接使用外部类所有的成员,包括私有的数据
public class person {
public static class Inner {
public void f() {
System.out.println("inner");
}
}
public static void main(String[] args) {
person a = new person();
Inner t = new Inner();
t.f();
person.Inner t1 = new Inner();
t1.f();
}
}
局部内部类
class 外部类{
方法(){
class 局部内部类{
}
}
{
class 局部内部类{
}
}
}
- 局部内部类,匿名内部类
- 局部内部类只能在声明它的方法或代码块使用
- 局部内部类的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
- 局部类内部可以使用外部成员变量的成员,包括私有的
- 局部内部类可以使用外部方法的局部变量,但必须是final的
- 局部内部类不能使用修饰符,与局部变量类似
- 不能使用static,因此不能包含静态成员
匿名内部类
匿名内部类不能定义任何静态成员,方法和类,只能创建匿名内部类的一个实例.一个匿名内部类一定在new后面 , 匿名类是不能有名字的类,它们不能被引用 , 隐含实现一个接口或一个类
new 父类构造器(实参列表) 或 实现接口(){
语句;
};
new 类名或接口名(){
重写方法;
}.方法(); //注意分号
- 匿名内部类必须继承父类或实现接口
- 匿名内部类只能有一个对象
- 匿名内部类对象只能使用多态形式引用
interface A {
public abstract void fun1();
}
public class Outer {
public static void main(String[] args) {
new Outer() {
public void fun1() {
System.out.println("111");
}
}.fun1();;//单方法,双分号
}
}
interface A {
public abstract void fun1();
public abstract void fun2();
}
public class Outer {
public static void main(String[] args) {
A o = new A() {
public void fun1() {
System.out.println("111");
}
public void fun2() {
System.out.println("222");
}
};
o.fun1();//多种方法
o.fun2();
}
}
interface A {
public abstract A fun1();
public abstract A fun2();
}
public class Outer {
public static void main(String[] args) {
A o = new A() {
public A fun1() {
return this;
}
public A fun2() {
System.out.println("222");
return this;
}
}.fun1().fun2();
;
}
}
TreeMap mao=new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Person2&&o2 instanceof Person2){
Person2 p1=(Person2) o1;
Person2 p2=(Person2) o2;
System.out.println("****");
return Integer.compare(p1.getAge(),p2.getAge());
}
throw new RuntimeException("ERROR");
}
});
异常
异常分类
ERROR:JAVA虚拟无法解决的严重问题 , 如系统内部错误,资源耗尽
EXCEPTION:编程错误或偶然的外部因素导致的一般性问题(编译时异常和运行时异常) , 如空指针访问,数组越界
try-catch
try{
//可能产生异常的代码
}
catch(ExceptionName1 e){
//处理代码
}
catch(ExceptionName2 e){
//处理代码
}
[finally{
//无论是否发生,都无条件得执行的语句,即使try中有return,先finally后return
}
]
String str="abc";
try {
int num=Integer.parseInt(str);
}catch (NumberFormatException e){
System.out.println("数值转换bug");
System.out.println(e.toString());//输出异常信息
}
finally {
System.out.println("一定执行");
}
str="123";
try {
int num=Integer.parseInt(str);
}catch (NumberFormatException e){
System.out.println("数值转换bug");
System.out.println(e.toString());
}
finally {
System.out.println("一定执行");
}
- try{}语句块选定捕获异常的范围
- catch(Exceptiontype e){}处理不同类型的异常
- 如果明确知道产生异常的类型,可将该异常类作为catch的参数,也可将其父类作为catch的参数
- 可以访问一个异常类的成员变量或调用它的方法
- getMessage()获取异常信息,返回字符串
- printStackTrace()获取异常类名和异常信息,以及异常出现的位置,返回值void
- finally语句为异常处理提供一个统一的出口对程序状态统一管理(如数据库连接,输入输出流关闭,socket连接JVM不能自动回收,需要手动进行资源释放)
- finally和catch语句是可选的
- catch 中的异常如果满足子父类关系,则要求子类一定声明到父类上面,否则报错
- 将编译时异常延迟到运行时出现
- try-catch结构可以嵌套
- 子类重写方法抛出异常的类型不大于父类被重写的方法抛出的异常的类型
- 如果父类中被重写的方法没有使用throws,则子类重写的方法也不能使用throws,只能使用try-catch
str="123";
try {
int num=Integer.parseInt(str);//try结构中定义变量,try结构外num不可用
}catch (NumberFormatException e){
System.out.println("数值转换bug");
System.out.println(e.toString());//返回异常信息
e.printStackTrace();//打印全部信息
System.out.println(e.getMessage());//throw new MyException("111"); message为111
}
不捕获异常的情况
- java本身可以捕获RuntimeException类或它的子类,并能编译通过,但运行时会发生异常使程序运行终止
- 如果发生的是IOExpection等类型的异常,必须捕获,否则编译错误
throws
如果一个方法可能生成某种异常,但是并不能确定如何处理,则应该显示地声明抛出异常,表示异常由方法调用者处理,throw语句可以声明抛出异常的列表,异常类型可以是方法中产生的异常类型,也可以是其父类,throw一个异常
public void readFile(String file)throws FileNotFoundException{
...
FileInputStream fis=new FileInputstream(file);
...
}
手动抛出异常
首先生成异常类对象,并通过throw抛出,抛至上级父函数,直到有try-catch处理
IOException e=new IOException();
throw e;
自定义异常类
- 自定义异常类都是RuntimeException的子类
- 需要编写几个重载的构造器
- 需要提供serialVersionUID
- 自定义的异常通过throw抛出
class MyException extends Exception{
static final long serialVersionUID=1111111L;
private int idnumber;
public MyException(String message,int id){
super(message);
this.idnumber=id;
}
public int getId(){
return idnumber;
}
}
public class MyExpTest{
public void regist(int num)throws MyException{
if(num<0)
throw new MyException("111");
else
System.out.println("222");
}
}
throws和throw区别
- throw表示抛出一个异常对象,生成异常对象的过程,声明在方法体内
- throws属于异常处理的一种方式,声明在方法的声明处
Q.E.D.