文章目录

  • 1. 数据类型、变量与常量
    • 1.1基本数据类型(primitive types)
      • 1.1.1 boolean
      • 1.1.2字符型
        • 1.1.2.1 转 义 字 符 含 义
      • 1.1.3整数类型
      • 1.1.4 浮点类型
    • 1.2引用类型( reference types )
    • 1.3 基本数据类型和引用类型区别
    • 1.4 标识符( Identifier)
  • 2. 运算符与表达式
    • 2.1运算符
      • 2.1.1具体说明
  • 3. 流程控制语句
  • 4. 数组
  • 1 .类、字段、方法
    • 1.1定义
    • 1.2 构造方法
    • 1.3 使用对象
    • 1.4方法重载( overload)
    • 1.5 this的使用
  • 2 .类的继承
    • 2.1字段
    • 2.2方法
    • 2.3 super 的使用
    • 2.4 父类对象与子类对象的转换
    • 2.5例子
  • 3 .包
    • 3.1 包的定义
    • 3.2 package 语句
    • 3.3 import 语句
    • 3.4 编译和运行包中的类
    • 3.5 CLASSPATH
  • 4 .访问控制符
    • 4.1 修饰符
    • 4.2 成员的访问控制符(权限修饰符)
    • 4.3 类的访问控制符
    • 4.4 setter 与getter
  • 5 .非访问控制符
    • 5.1 static
      • 5.1.1 static 字段
      • 5.1.2 static 方法
      • 5.1.3 import static
    • 5.2 final
    • 5.3 abstract
  • 6 .接口
    • 6.1 定义
    • 6.2 接口的作用
    • 6.3 接口的实现
    • 6.4 接口类型
    • 6.5 接口中的常量
  • 7 .枚举
  • 8. Java8 中的接口
  • 1 . 变量及其传递
    • 1.1 基本类型变量与引用型变量
    • 1.2 字段变量与局部变量
    • 1.2 变量的传递
    • 1.3变量的返回
    • 不定长参数
  • 2 . 多态和虚方法调用
    • 2.1多态
    • 2.2上溯造型
    • 2.3虚方法调用
  • 3 . 对象构造与初始化
    • 3.1 构造方法(constructor)
    • 3.2 创建对象时初始化
    • 3.3 实例初始化与静态初始化
    • 3.4 构造方法的执行过程
  • 4 . 对象清除与垃圾回收
    • 4.1 对象的自动清除
    • System.gc ()方法
    • finalize() 方法
    • try -with-resources
  • 5 . 内部类与匿名类
    • 定义
    • 内部类(Inner class)
    • 局部类
    • 匿名类
  • 6 . Lambda表达式
  • 7 . 装箱、枚举、注解
    • 基本类型的包装类
    • 装箱与拆箱
    • 枚举
    • 注解
  • 8 . 没有指针的Java语言
    • java中相等还是不等

1. 数据类型、变量与常量

数据类型决定数据的存储方式和运算方式
Java中的数据类型分为两大类

1.1基本数据类型(primitive types)

Java中定义了四类/八种基本数据类型
整数型---- byte, short, int, long
浮点数型---- float, double
逻辑型---- boolean
字符型---- char

1.1.1 boolean

boolean类型适于逻辑运算,一般用于程序流程控制
boolean类型数据只允许取值true或false,不可以0或非0的整数替代true和false
if(a=5)在java中是不允许的

用法举例:
boolean b = false;
if(b==true)  {
//do
}
1.1.2字符型

char型数据用来表示通常意义上“字符”
字符常量是用单引号括起来的单个字符
char c = ‘A’;
Java字符采用Unicode编码,每个字符占两个字节,可用十六进制编码形式表示 char c1 = ‘\u0061’;
Java语言中还允许使用转义字符’'来将其后的字符转变为其它的含义
char c2 = ‘\n’; //代表换行符

1.1.2.1 转 义 字 符 含 义

\ddd 1到3位八进制数所表示的字符(ddd)
\uxxxx 1到4位十六进制数所表示的字符(xxxx)
\' 单引号字符
\" 双引号字符
\ 反斜杠字符
\r 回车
\n 换行
\f 走纸换页
\t 横向跳格
\b 退格

1.1.3整数类型

Java各整数类型有固定的表数范围和字段长度,而不受具体操作系统的 影响,以保证Java程序的可移植性
byte 1字节 -128 ~ 127
short 2字节 -2^15 ~ 2 ^15-1
int 4字节 -2 ^ 31 ~ 2^31-1
long 8字节 -2^63 ~ 2 ^63-1
Java语言整型常量的三种表示形式:
十进制整数,如12, -314, 0。
八进制整数,要求以0开头,如012
十六进制数,要求0x或0X开头,如0x12
二进制数,以0b或0B开头,如0b00010010 (Java7以上)
Java语言的整型常量默认为int型,
如: int i =3;
声明long型常量可以后加‘ l ’或‘ L ’ ,
如:long l = 3L;
Java中没有“无符号数” 可以用long来处理无符号整数(uint)

1.1.4 浮点类型

Java浮点类型有固定的表数范围和字段长度
float 4字节 -3.403E38~3.403E38
double 8字节 -1.798E308~1.798E308
Java浮点类型常量有两种表示形式
十进制数形式,必须含有小数点,
例如: 3.14 314.0 .314
Java7以上: 123_456.789_000 (千分位分割符用下划线表示)
科学记数法形式,如 3.14e2 3.14E2 314E2
Java浮点型常量默认为double型, 如要声明一个常量为float型,则需在数字后面加f或F,
如: double d = 3.14; float f = 3.14f;

1.2引用类型( reference types )

类(class)
接口(interface)
数组

1.3 基本数据类型和引用类型区别

基本类型: 变量在栈,在“这里”
引用类型: 变量引用到堆,在“那里”
double d = 3; Person p = new Person();
赋值时 double d2 = d; 复制的是值
Person p2 = p; 复制的是引用

1.4 标识符( Identifier)

名字就是标识符:任何一个变量、常量、方法、对象和类都需要有名字
标识符要满足如下的规定
(1)标识符可以由字母、数字和下划线(_)、美元符号($)组合而成; (2)标识符必须以字母、下划线或美元符号开头,不能以数字开头。
标识符最好与其意义相符,以增加程序的可读性
应注意Java是大小写敏感的语言。
按Java惯例
1.类名首字母用大写(Pascal)
2.其余的(包名、方法名、变量名)首字母都小写(camel)
3.少用下划线
4.变量、常量随使用随定义

2. 运算符与表达式

2.1运算符

算术运算符: +,―,,/,%,++,-
关系运算符: >,<,>=,<=,==,!=
逻辑运算符: !,& , | , ^ , &&,||
位运算符: &,|,^,~ , >>,<<,>>>
赋值运算符: =
扩展赋值运算符:+=,―=,
=,/=
字符串连接运算符: +

2.1.1具体说明

左移 "a<<b; "将二进制形式的a逐位左移b位,最低位空出的b位补0;
带符号右移 "a>>b; "将二进制形式的a逐位右移b位,最高位空出的b位补原来的符号位;
无符号右移 "a>>>b;"将二进制形式的a逐位右移b位,最高位空出的b位补0
移位运算符性质
适用数据类型:byte、short、char、int、long
对低于int型的操作数将先自动转换为int型再移位(整型提升,对所有的运算 都是这样)
对于int型整数移位a>>b,系统先将b对32取模,得到的结果才是真正移位的 位数
对于long型整数移位时a>>b ,则是先将移位位数b对64取模
赋值运算符=
当“=”两侧的数据类型不一致时,可以适用默认类型转换或强制类型转换 (casting)原则进行处理
long ll = 100; int i = (int)ll;
特例:可以将整型常量直接赋值给byte, short, char等类型变量,而不需要进 行强制类型转换,只要不超出其表数范围
byte b = 12; //合法 byte b = 4096; //非法

"+" 除用于算术加法运算外,还可用于对字符串进行连接操作
int i = 300 +5;
String s = "hello, " + “world!”;
"+"运算符两侧的操作数中只要有一个是字符串(String)类型,系统会自动将另一 个操作数转换为字符串然后再进行连接

 int i = 300 +5; String s = "hello, " + i + "号";System.out.println(s);   //输出:hello, 305号

表达式
表达式是符合一定语法规则的运算符和操作数的序列
a
5.0 + a
(a-b)*c-4
i<30 && i%10!=0
表达式的类型和值
对表达式中操作数进行运算得到的结果称为表达式的值
表达式的值的数据类型即为表达式的类型
表达式的运算顺序
首先应按照运算符的优先级从高到低的顺序进行
优先级相同的运算符按照事先约定的结合方向进行
当有不同种类的混合运算时:
int->long->float->double
整型提升
所有的byte, short, char 参与算术运算等转为int

3. 流程控制语句

没有“表达式语句”这个概念 x+y;是不合法的
方法调用语句
赋值语句,注意分号(;)
分支语句
循环语句
类似c++

4. 数组

数组是多个相同类型数据的组合
一维数组的声明方式:
int[] a;
double []b
Mydate []c;
注意方括号写到变量名的前面,也可以写到后面

数组定义 与 为数组元素分配空间 分开进行
Java语言中声明数组时不能指定其长度(数组中元素的个数),
例如: int a[5]; //非法
数组是引用类型
int [ ] a = new int[5];
这里 a 只是一个引用
静态初始化
在定义数组的同时就为数组元素分配空间并赋值。

int[] a = { 3, 9, 8};
或写为 int[] a = new int[]{ 3, 9,  8 };MyDate[]  dates= {
new MyDate(22, 7, 1964),
new MyDate(1, 1, 2000),
new MyDate(22, 12, 1964)
};

默认初始化

数组一经分配空间,其中的每个元素也被按照成员变量同样的方式被 隐式初始化。例如: ( 数值类型是0, 引用类型是null )
int []a= new int[5]; //a[3]则是0

数组元素的引用

数组元素的引用方式
index为数组元素下标,可以是整型常量或整型表达式。
如a[3] , b[i] , c[6*i];
数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 ~ n-1;
每个数组都有一个属性length指明它的长度,
例如:a.length 指明数组a的 长度(元素个数);

 int[] ages = new int[10]; for ( int i=0; i<ages.length; i++ ) { System.out.println( ages[i] ); }

Enhanced for语句可以方便地处理数组、集合中各元素

int[] ages = new int[10];
for ( int age : ages )
{ System.out.println( age );
} //这种语句是只读式的遍历

System.arraycopy方法提供了数组元素复制功能:

 //源数组 int[] source = { 1, 2, 3, 4, 5, 6 }; // 目的数组 int []dest = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; // 复制源数组中从下标0开始的source.length个元素到目的数组,//从下标0的位置开始存储。 // System.arraycopy( source, 0, dest, 0, source.Length );

public static void arraycopy(Object src,int srcPos,Object dest,int destPos, int length)
其中:src表示源数组,srcPos表示源数组要复制的起始位置,desc表示目标数组,length表示要复制的长度。
二维数组
int [][] t = new int [3][];
t[0] = new int[2];
t[1] = new int[4];
t[2] = new int[3];
多维数组的声明和初始化应按从高维到低维的顺序进行
int t1[][] = new int [][4]; // 非法 , 这与 C++ 不同

1 .类、字段、方法

1.1定义

类是组成Java程序的基本要素,
一类对象的原型
封装了一类对象的状态和方法
它将变量与函数封装到一个类中

class Person { String name; int age; void sayHello(){ System.out.println("Hello!  My name is" + name ); }
}

字段(field)是类的属性,是用变量来表示的。
字段又称为域、域变量、属性、成员变量等
方法(method)是类的功能和操作, 是用函数来表示的

1.2 构造方法

构造方法(constructor )是一种特殊的方法
用来初始化(new)该类的一个新的对象
构造方法和类名同名,而且不写返回数据类型

   Person( String n, int a ){ name = n; age = a; }

一般情况下,类都有一个至多个构造方法
如果没有定义任何构造方法,系统会自动产生一个构造方法,称为默 认构造方法(default constructor)。
默认构造方法不带参数,并且方法体为空。

1.3 使用对象

访问对象的字段或方法,需要用算符“.” :

   Person p = new Person(); System.out.println( p.name ); p.sayHello();

这种使用方式的好处 封装性 安全性

1.4方法重载( overload)

方法重载(overloading):多个方法有相同的名字,编译时能识别出 来。
这些方法的签名(signature)不同,或者是参数个数不同,或者是参 数类型不同。
通过方法重载可以实现多态(polymorphism)

1.5 this的使用

1.在方法及构造方法中,使用this来访问字段及方法
例如,方法sayHello中使用name和使用this.name是相同的。即:

   void sayHello(){ System.out.println("Hello!  My name is " + name ); } 与 void sayHello(){ System.out.println("Hello!  My name is " + this.name ); } 的含义是相同的。

this指当前对象实例本身
2.使用this解决局部变量与域同名的问题
使用this还可以解决局部变量(方法中的变量)或参数变量与域变 量同名的问题。如,在构造方法中,经常这样用:

  Person( int age, String name ) { this.age = age; //前一个是当前字段的age,后面是表示当前的局部变量int agethis.name = name; }

这里,this.age表示域变量,而age表示的是参数变量。

3.构造方法中,用this调用另一构造方法

构造方法中,还可以用this来调用另一构造方法。如:

 Person(  ) { this( 0, "" ); //一个构造方法中调用另一个构造方法…… }

在构造方法中调用另一构造方法,则这条调用语句必须放在第一句。

2 .类的继承

继承(inheritance)是面向对象的程序设计中最为重要的特征之一
子类(subclass),父类或超类(superclass)
父类包括所有直接或间接被继承的类
Java支持单继承:一个类只能有一个直接父类。

子类继承父类的状态和行为
可以修改父类的状态或重载父类的行为
可以添加新的状态和行为。
好处
可以提高程序的抽象程度
实现代码重用,提高开发效率和可维护性

Java中的继承是通过extends关键字来实现的
class Student extends Person {
……
}
如果没有extends子句,则该类默认为java.lang.Object的子类。
所有的类都是通过直接或间接地继承java.lang.Object得到的。
所有对象都可以用他的 toString方法转换成字符串,都可以克隆

类Student从类Person继承:

   class  Student  extends Person { String school; int score; boolean isGood(){ return score>80; } //… }

2.1字段

1.字段的继承
子类可以继承父类的所有字段
Student自动具有Person的属性(name,age)
2. 字段的隐藏
子类重新定义一个与从父类那里继承来的域变量完全相同的变量,称为域的隐藏。域的隐藏在实际编程中用得 较少。
3. 字段的添加
定义子类时,加上新的域变量,就可以使子类比父类多一些属性。如:在定义子类时,加上新的域变量,就可以使子类比父类多一些属性。如:

class  Student extends Person
{ String school; int score;
}

2.2方法

1.方法的继承
父类的非私有方法也可以被子类自动继承。如,Student自动继承Person的方 法sayHello和isOlderThan。
2.方法的覆盖(Override)(修改)
子类也可以重新定义与父类同名的方法,实现对父类方法的覆盖

 void sayHello(){System.out.println("Hello!  My name is " + name + ". My school is " + school );}

通过方法的覆盖,能够修改对象的同名方法的具体实现方法。
3.方法的添加
子类可以新加一些方法,以针对子类实现相应的功能。
如,在类Student中,加入一个方法,对分数进行判断:

boolean isGoodStudent(){
return score>=90;}

4 . 方法的重载
一个类中可以有几个同名的方法,这称为方法的重载(Overload)。
同时,还可以重载父类的同名方法
与方法覆盖不同的是,重载不要求参数 类型列表相同。
重载的方法实际是新加的方法
如,在类Student中,重载一个名为sayHello的方法:

void sayHello( Student another ){ System.out.println("Hi!"); if( school .equals( another.school )) System.out.println(" Shoolmates "); }

2.3 super 的使用

1.使用super访问父类的域和方法
注意:正是由于继承,使用this可以访问父类的域和方法。但有时为了明确地指明父类的域和方法,就要用关 键字super。
例如:父类Student有一个域age,在子类Student中用age, this.age, super.age来访问age是完全一样的:

 void testThisSuper(){ int a; a = age; a = this.age; //是当前的agea = super.age;//指明了是父类的age}

当然,使用super不能访问在子类中添加的域和方法。

有时需要使用super以区别同名的域与方法
使用super可以访问被子类所隐藏了的同名变量
又如,当覆盖父类的同名方法的同时,又要调用父类的方法,就必须使用super。
如:

 void sayHello(){ super.sayHello(); System.out.println( "My school is " + school ); }

**在覆盖父类的方法的同时,又利用已定义好的父类的方法。**批判性的继承

2.使用父类的构造方法
构造方法是不能继承的
比如,父类Person有一个构造方法Person(String, int),不能说子类Student也自动有一个构造方法Student(String, int)。所以子类要从新定义构造方法
但是,子类在构造方法中,可以用super来调用父类的构造方法

  Student(String name, int age, String school ){ super( name, age ); this.school = school; }

使用时,super()必须放在第一句。

2.4 父类对象与子类对象的转换

类似于基本数据类型数据之间的强制类型转换,存在继承关系的父类对象和 子类对象之间也可以在一定条件下相互转换。
(1) 子类对象可以被视为其父类的一个对象
如一个Student对象也是一个Person对象。
(2) 父类对象不能被当做其某一个子类的对象。找一个学生不能随便拉来一个人
(3) 如果一个方法的形式参数定义的是父类对象,那么调用这个方法时,可以使用子类对象作为实际参数。
需要一个人,实际传过来一个学生,也是可以的
(4) 如果父类对象引用指向的实际是一个子类对象,那么这个父类对象的引 用可以用强制类型转换(casting)成子类对象的引用。

2.5例子

class Person {
String name;
int age;Person( String n, int a ){name = n;age = a;
}Person( String n ){name = n;age = 0;
}Person( int age, String name )
{this.age = age;this.name = name;
}Person(  ){this( 0, "" );
}boolean isOlderThan( int anAge ){return this.age > anAge;
}void sayHello(){System.out.println("Hello! My name is " + name );
}void sayHello( Person another ){System.out.println("Hello," + another.name + "! My name is " + name );
}public static void main(String[] args)
{Person p = new Person("Li Min", 18);Person p2 = new Person("Wang Qiang", 20 );p.sayHello();p.sayHello(p2);
}
}
class  Student extends Person
{String school;int score;void sayHello( Student another ){System.out.println("Hi!");if( school == another.school ) System.out.println(" Shoolmates ");}boolean isGoodStudent(){return score>=90;}void sayHello(){super.sayHello();System.out.println( "My school is " + school );}Student(String name, int age, String school ){super( name, age );this.school = school;}Student(){}void testThisAndSuper(){int a;a = age;a = this.age;a = super.age;}public static void main( String [] arggs ){Person p = new Person( "Liming", 50 );Student s = new Student( "Wangqiang", 20, "PKU" );Person p2 = new Student( "Zhangyi", 18, "THU" );Student s2 = (Student) p2;//强制转换//Student s3 = (Student) p;  //runtime exception p.sayHello( s );Person [] manypeople = new Person[ 100 ];manypeople[0] = new Person("Li", 18 );manypeople[1] = new Student("Wang", 18, "PKU");}
}

3 .包

3.1 包的定义

package pkg1[.pkg2[.pkg3…]];
包及子包的定义,实际上是为了解决名字空间、名字冲突
它与类的继承没有关系。
事实上,一个子类与其父类可以位于不同的包中。
包有两方面的含义
一是名字空间、存储路径(文件夹)、
一是可访问性同一包中的各个类,默认情况下可互相访问

3.2 package 语句

包层次的根目录是由环境变量CLASSPATH来确定的。
在简单情况下,没有package语句,这时称为无名包(unnamed package)
在Eclipse中,也叫(default package)。
Java的JDK提供了很多包
java.applet,java.awt,java.awt.image,java.awt.peer,java.io, java.lang,java.net,java.util,javax.swing,等

3.3 import 语句

为了能使用Java中已提供的类,需要用import语句来导入所需要的类

 import语句的格式为: import package1[.package2…]. (classname |*); 例如: import  java.util.Date; 这样,程序中 java.util.Date可以简写为Date import  java.awt.*; import java.awt.event.*; 注意:使用星号(*)只能表示本层次的所有类,不包括子层次下的类。

Java编译器自动导入包java.lang.* 所以不用写math类,
Eclipse等IDE可以方便地生成import语句

3.4 编译和运行包中的类

使用javac可以将.class文件放入到相应的目录,只需要使用一个命令选项-d来指明包的根目录即可。
javac -d d:\tang\ch04 d:\tang\ch04\pk\TestPkg.java
javac -d . pk*.java
其中,“.”表示当前目录
运行该程序,需要指明含有main的类名
java pk.TestPkg

3.5 CLASSPATH

在编译和运行程序中,经常要用到多个包,怎样指明这些包的根目录呢
简单地说,包层次的根目录是由环境变量CLASSPATH来确定的。
具体操作 有两种方法。
一是在java及javac命令行中,用-classpath(或-cp)选项来指明,如:
java –classpath d:\tang\ch04;c:\java\classes;. pk.TestPkg
二是设定classpath环境变量,用命令行设定环境变量,如:
set classpath= d:\tang\ch04;c:\java\classes;.

4 .访问控制符

4.1 修饰符

加到类的名字或字段的名字之前修饰一下
修饰符(modifiers)分为两类
访问修饰符(access modifiers)
如public/private等
其他修饰符
如abstract等
可以修饰类、也可以修饰类的成员(字段、方法)

4.2 成员的访问控制符(权限修饰符)

可见性,默认类似于c++里的友元,十分方便

同一个类中 同一个包中 不同包中的子类 不同包中的非子类
private YES
默认 (包可访问) YES YES
protected YES YES YES
public YES YES YES YES

4.3 类的访问控制符

在定义类时,也可以用访问控制符。
类的访问控制符或者为public,或者默认没有private
若使用public,其格式为:
public class 类名{
……
}
如果类用public修饰,则该类可以被其他类所访问
若类默认访问控制符,则该类只能被同包中的类访问

4.4 setter 与getter

将字段用private修饰,从而更好地将信息进行封装和隐藏。
用setXXXX和getXXXX方法对类的属性进行存取,分别称为setter与getter。 字段是private,方法可以是public
这种方法有以下优点
(1)属性用private更好地封装和隐藏,外部类不能随意存取和修改
(2)提供方法来存取对象的属性,在方法中可以对给定的参数的合法性进行检验。
(3)方法可以用来给出计算后的值。
(4)方法可以完成其他必要的工作(如清理资源、设定状态,等等)。
(5)只提供getXXXX方法,而不提供setXXXX方法,可以保证属性是只读的。无法修改

Setter/getter 示例

 class  Person2
{ private int age; public void setAge( int age ){ if (age>0 && age<200) this.age = age; } public int getAge(){ return age; }
}

尽量不要把字段直接暴露出来,这样就很好

5 .非访问控制符

基 本 含 义 修 饰 类 修 饰 成 员 修饰局部变量
static 静态的、非实例的、类的 可以修饰内部类 Yes
final 最终的、不可改变的 Yes Yes Yes
abstract 抽象的、不可实例化的 Yes Yes

5.1 static

5.1.1 static 字段

静态字段最本质的特点是:
它们是类的字段,不属于任何一个对象实例。
它不保存在某个对象实例的内存区间中,而是保存在类的内存区域的公共存储单元。
类变量可以通过类名直接访问,也可以通过实例对象来访问,两种方法的结果是相同的。 实例对象也是属于某一个类的
如System类的in和out对象,就是属于类的域,直接用类名来访问, 即System.in和System.out。
例子
在类Person中可以定义一个类域为totalNum:

 class Person { static long totalNum; int age; String Name;
}

totalNum代表人类的总人数,它与具体对象实例无关。可以有两种方法来 访问:Person.totalNum和p.totalNum (假定p是Person对象,实例)。
在一定意义上,可以用来表示全局变量

5.1.2 static 方法

用static修饰符修饰的方法仅属于类的静态方法,又称为类方法
与此相对,不用static修饰的方法,则为实例方法
类方法的本质是该方法是属于整个类的,不是属于某个实例的

声明一个方法为static有以下几重含义。
(1) 非static的方法是属于某个对象的方法,在这个对象创建时,对象 的方法在内存中拥有自己专用的代码段。而static的方法是属于整个类 的,它在内存中的代码段将随着类的定义而进行分配和装载,不被任 何一个对象专有。

(2) 由于static方法是属于整个类的,所以它不能操纵和处理属于某个对象 的成员变量,而只能处理属于整个类的成员变量,即static方法只能处理本类中的static域或调用static方法。

(3) **static方法中,不能访问实例变量,不能使用this 或super。**因为this和super是具体的当前的某一个实例的,而static是属于整个类的

(4) 调用这个方法时,应该使用类名直接调用,也可以用某一个具体的对象 名。
例如:Math.random(),Integer.parseInt()等就是类方法,直接用类名进行访问,他不是实例方法

5.1.3 import static

import static java.lang.System.*;
有一个类成员都是static
out.println();表示System.out.println();

5.2 final

1.final类
如果一个类被final修饰符所修饰和限定,说明这个类不能被继承,即不可能有 子类。 可以进行优化
2.final方法
final修饰符所修饰的方法,是不能被子类所覆盖的方法
3. final字段、final局部变量(方法中的变量)
它们的值一旦给定,就不能更改。
只读量,它们能且只能被赋值一次,而不能被赋值多次。
一个字段被static final两个修饰符所限定时,它可以表示常量
如Integer. MAX_VALUE(表示最大整数)、Math.PI(表示圆周率)就是这种常量。

关于赋值

1.在定义static final域时,若不给定初始值,则按默认值进行初始化(数值为0,boolean型为false,引用型为 null)。

2.在定义final字段时,若不是static的域,则必须且只能赋值一次,不能缺省。
这种域的赋值的方式有两种:一是在定义变量时赋初始值,二是在每一个构造函数中进行赋值

3.在定义final局部变量时,也必须且只能赋值一次。它的值可能不是常量,但它的取值在变量存在期间不会改变。(只读的)

5.3 abstract

1 . abstract类
凡是用abstract修饰符修饰的类被称为抽象类。
抽象类不能被实例化 ,不能new一个实例对象

2.abstract方法
被abstract所修饰的方法叫抽象方法,抽象方法的作用在为所有子类定义一个统一的 接口。对抽象方法只需声明,而不需实现,即用分号(;)而不是用{},格式如下:
abstract returnType abstractMethod( [paramlist] );

抽象类中可以包含抽象方法,也可以不包含abstract方法。但是,一旦某个类中包含 了abstract方法,则这个类必须声明为abstract类。

抽象方法在子类中必须被实现,否则子类仍然是abstract的。

6 .接口

6.1 定义

接口,某种特征的约定 ,约定特征,引用类型
定义接口 interface
所有方法都自动是public abstract的 ,公开不考虑实现
这个特征可以被不同的类所实现,使用接口时候可以用某个具体对象代替他
实现接口 implements
可以实现多继承
与类的继承关系无关
面向接口编程,而不是面向实现
Flyable f = new Bird();
Java中有大量的接口

6.2 接口的作用

1 . 通过接口可以实现不相关类的相同行为,(超人,鸟,飞机相同行为是可飞行)而不需要考虑这些类之间 的层次关系。从而在一定意义上实现了多重继承。 (可以让一个类实现多个特征,可飞翔,可复制。。。)
2. 通过接口可以指明多个类需要实现的方法
3. 通过接口可以了解对象的交互界面,而不需了解对象所对应的类
示例
下面我们给出一个接口的定义: 实现方法都是public

 interface Collection { void add (Object obj); void delete (Object obj); Object find (Object obj); int size ( ); }

通常接口以able或ible结尾,表明接口能完成一定的行为。
接口声明中还可以包括对接口的访问权限以及它的父接口列表。完整的接口声明如下:
[public] interface interfaceName [extends listOfSuperInterface]{
……
}
其中public指明任意类均可以使用这个接口,缺省情况下,只有与该接口定义在同一个包中的类才可以访问这个接口。
extends 子句与类声明中的extends子句基本相同,不同的是一个接口可以有多个父接口, 用逗号隔开,而一个类只能有一个父类子接口继承父接口中所有的常量和方法。

方法定义的格式为:
returnType methodName ( [paramlist] );
接口中只进行方法的声明,而不提供方法的实现,所以,方法定义没有方法体,且用分号(;)结尾。在接口中声明的方法具有public 和 abstract属性。
所以定义的时候这两个关键词是可以省略
另外,如果在子接口中定义了和父接口同名的常量或相同的方法,则 父接口中的常量被隐藏,方法被重载。

6.3 接口的实现

在类的声明中用implements子句来表示一个类使用某个接口,在类体中可以使用接口中定义的常量,而且必须实现接口中定义的所有方法。一个类可以实现多个接口。

下面我们在类FIFOQueue中实现上面所定义的接口collection:

class FIFOQueue implements collection{
public void add ( Object obj ){……}public void delete( Object obj ){……}public Object find( Object obj ){……}public  int currentCount{……}

在类中实现接口所定义的方法时,方法的声明必须与接口中所定义的完全一致。

6.4 接口类型

接口可以作为一种引用类型来使用。任何实现该接口的类的实例都可以存储在该接口类型的变量中,通过这些变量可以访问类所实现的接口中的方法。Java运行时系统动态地确定该使用哪个类中的方法。
把接口作为一种数据类型可以不需要了解对象所对应的具体的类,以 前面所定义的接口Collection和实现该接口的类FIFOQueue为例,下例中,我们以Collection作为引用类型来使用。

 public static void main( String args[] ){ Collection c = new FIFOQueue();…… c.add( obj ); …… }

6.5 接口中的常量

接口体中可以包含常量定义
常量定义的格式为:
type NAME = value;
其中type可以是任意类型,NAME是常量名,通常用大写,value是 常量值。
在接口中定义的常量可以被实现该接口的多个类共享,它与 C中用 #define以及C++中用const定义的常量是相同的。
在接口中定义的常量具有public, static, final的属性。(可以省略)

7 .枚举

从JDK1.5起,可以使用枚举
enum Light {
Red, Yellow, Green
}
使用
Ligth light = Light.Red;
switch( light ) {
case Red:
…… Break;
}
注意:case后面不写为 Light.Red
Java中的枚举是用class来实现的,可以复杂地使用

8. Java8 中的接口

Java8以上,接口成员还可以是:
static方法
具有实现体的方法 (default方法)
默认方法的好处是:提供了一个默认实现,子类在implements可以不用再重新写了

1 . 变量及其传递

1.1 基本类型变量与引用型变量

基本类型(primitive type):其值直接存于变量中。“在这里”
引用型(reference type) 的变量(class,interface,数组)除占据一定的内存空间外,它所引用 的对象实体(由new 创建)也要占据一定空间。“在那里”
引用变量在这里只是存一个对象实体的地址,通过这个引用能够操作这个对象

 MyDate m,n;m=new MyDate();n=m;n.addYear();

.

 public class MyDate {private int day;private int month;private int year;public MyDate(int y, int m, int d) {year = y;month = m;day = d;}     void addYear(){year ++;}public void display() {System.out.println(year + "-" + month + "-" +day);  }public static void main(String[] args) {MyDate m = new MyDate(2003, 9, 22);MyDate n = m;//复制只是复制了一个引用n.addYear();m.display();//操作的是同一个对象n.display();}
}

1.2 字段变量与局部变量

字段变量(field)与局部变量(Local variable)
前者是在类中,后者是方法中定义的变量或方法的参变量
从内存角度看
存储位置,字段变量为对象的一部分、存在于堆中的,局部变量是存在于栈中。
生命周期不同 字段变量随着对象的存在而存在,局部变量随着方法的存在而存在,随着方法的结束而结束
初始值:字段变量可以自动赋初值,局部变量则须显式赋值

 class Test() { int a; void m(){ int b; System.out.println(b);//编译不能通过需要初始化。 } }

从语法角度看
字段变量属于类,可以用public,private,static,final 修饰。
局部变量不能够被访问控制符及static修饰
都可以被final修饰

1.2 变量的传递

调用对象方法时,要传递参数。在传递参数时,
Java 是值传递,即,是将表达式的值复制给形式参数。
对于引用型变量,传递的值是引用值,而不是复制对象实体
可以改变对象的属性

1.3变量的返回

方法的返回:
返回基本类型。
返回引用类型。它就可以存取对象实体。

Object getNewObject() { Object obj=new Object(); return obj; }

调用时:Object p= GetNewObject();

不定长参数

不定长参数(Variable length arguments),从JDK1.5开始
用省略号表示, 并且是最后一个参数
实际上Java当成一个数组

  int sum( int … nums){ int s=0; for(int n : nums) s+=n; return s; }

调用:sum(1,2,3,4);
又例如: public static void main( String…argv)

2 . 多态和虚方法调用

2.1多态

多态(Polymorphism)是指一个程序中相同的名字表示不同的含义的情况。
多态有两种情形
编译时多态:
重载(overload) (多个同名的不同方法)。
如 p.sayHello(); p.sayHello(“Wang”);
运行时多态:
覆盖(override) (子类对父类方法进行覆盖)
动态绑定(dynamic binding) ----虚方法调用(virtual method invoking)
在调用方法时,程序会正确地调用子类对象的方法。
多态的特点大大提高了程序的抽象程度和简洁性

2.2上溯造型

上溯造型(upcasting)
是把派生类型当作基本类型处理
例子见下面博客
https://blog.csdn.net/weijie_home/article/details/49105871

Person p = new Student(); void fun(Person p ){…}        fun(new Person());

2.3虚方法调用

什么是虚方法?
https://blog.csdn.net/vop444/article/details/69525124#commentBox
虚方法例子:
https://blog.csdn.net/qq_32863631/article/details/79227859
用虚方法调用,可以实现运行时的多态!
子类重载了父类方法时,运行时
运行时系统根据调用该方法的实例的类型(传进去的时student,那么就调用student)来决定选择哪个方法调用
所有的非final方法都会自动地进行动态绑定
什么是动态绑定?
https://blog.csdn.net/javamoo/article/details/78776150
虚方法调用示例

class TestStaticInvoke
{static void doStuff( Shape s ){s.draw();}public static void main( String [] args ){Circle c = new Circle();Triangle t = new Triangle();Line l = new Line();doStuff(c);doStuff(t);doStuff(l);Shape s = new Circle();doStuff(s);s.draw();Circle c2 = new Circle();c2.draw();}
}
class Shape
{void draw(){ System.out.println("Shape Drawing"); }
}
class Circle extends Shape
{void draw(){ System.out.println("Draw Circle"); }
}class Triangle extends Shape
{void draw(){ System.out.println("Draw Three Lines"); }
}class Line extends Shape
{void draw(){ System.out.println("Draw Line"); }
}
//输出:
//Draw Circle
//Draw Three Lines
//Draw Line
//Draw Circle
//Draw Circle
//Draw Circle

动态类型确定
变量 instanceof 类型
结果是boolean 值(实际就是这个类型或者是他的子类型,则返回true)
对实际类型进行判断
例子:

class Instanceof
{public static void main(String[] args) {Object [] things = new Object[3];//object所有类的父类things[0] = new Integer(4);things[1] = new Double(3.14);things[2] = new String("2.09");double s = 0;for( int i=0; i<things.length; i++ ){if( things[i] instanceof Integer )//看看是不是属于这个类型s += ((Integer)things[i]).intValue();//强制类型转换else if( things[i] instanceof Double )s += ((Double)things[i]).doubleValue();}System.out.println("sum=" + s);}
}
//输出:sum=7.140000000000001

什么情况不是虚方法调用

Java中,普通的方法是虚方法
(在调用过程中会根据实际的对象来决定方法的调用)
但static,private方法不是虚方法调用 (static是属于类的,private是属于这个类自己的)
static,private与虚方法编译后用的指令是不同的

package text1;public class JavaP3methods {void f(){}private void p(){}static void s(){}public static void main(String...argv){JavaP3methods obj = new JavaP3methods();obj.f();obj.p();obj.s();}
}

反汇编代码:

Compiled from "JavaP3methods.java"
public class text1.JavaP3methods {public text1.JavaP3methods();Code:0: aload_01: invokespecial #8                  // Method java/lang/Object."<init>":()V4: returnvoid f();Code:0: returnstatic void s();Code:0: returnpublic static void main(java.lang.String...);Code:0: new           #1                  // class text1/JavaP3methods3: dup4: invokespecial #19                 // Method "<init>":()V7: astore_18: aload_19: invokevirtual #20                 // Method f:()V12: aload_113: invokespecial #22                 // Method p:()V16: invokestatic  #24                 // Method s:()V19: return
}

三种非虚的方法
static的方法,以声明的类型为准,与实例类型无关
private方法子类看不见,也不会被虚化
final方法子类不能覆盖,不存在虚化问题

class example
{static void doStuff( Shape s ){s.draw();}public static void main( String [] args ){Circle c = new Circle();Triangle t = new Triangle();Line l = new Line();doStuff(c);doStuff(t);doStuff(l);Shape s = new Circle();doStuff(s);s.draw();Circle c2 = new Circle();//可见static是非虚的,只跟声明的类型有关c2.draw();}
}
class Shape
{static void draw(){ System.out.println("Shape Drawing"); }
}
class Circle extends Shape
{static void draw(){ System.out.println("Draw Circle"); }
}class Triangle extends Shape
{static void draw(){ System.out.println("Draw Three Lines"); }
}class Line extends Shape
{static void draw(){ System.out.println("Draw Line"); }
}//输出:
//Shape Drawing
//Shape Drawing
//Shape Drawing
//Shape Drawing
//Shape Drawing
//Draw Circle

3 . 对象构造与初始化

3.1 构造方法(constructor)

对象都有构造方法
如果没有,编译器加一个default构造方法 (默认构造方法什么都不干)
抽象类也有构造方法,任何一个对象都需要构造

调用本类或父类的构造方法

this调用本类的其他构造方法。
super调用直接父类的构造方法
this或super要放在第一条语句,且只能够有一条
如果没有this及super,则编译器自动加上super(),即调用直接父类 不带参数的构造方法
因为必须令所有父类的构造方法都得到调用,否则整个对象的构建就 可能不正确。

例子:

class example2
{public static void main(String[] args){ Person p = new Graduate();}
}class Person
{String name; int age;Person(){}Person( String name, int age ){this.name=name; this.age=age; System.out.println("In Person(String,int)");}
}class Student extends Person
{String school;Student(){this( null, 0, null );System.out.println("In Student()");}Student( String name, int age, String school ){super( name, age );this.school = school;System.out.println("In Student(String,int,String)");}
}class Graduate extends Student
{String teacher="";Graduate(){//super();System.out.println("In Graduate()");}
}//输出结果:
//In Person(String,int)
//In Student(String,int,String)
//In Student()
//In Graduate()

上面代码可见虽然只写了一个new,但是它是一直调用父类的构造方法,直到object

  class A { A(int a){} } class B extends A { B(String s){} //编译不能够通过.}

编译器会自动调用B(String s){ super();} 他会调用不带参数的构造方法,但是父类没有不带参数的,所以出错.
解决方法:
在B的构造方法中,加入super(3);
在A中加入一个不带参数的构造方法,A(){}
去掉A中全部的构造方法,则编译器会自动加入一个不带参数的构造方法,称为默认的构造方法

3.2 创建对象时初始化

p = new Person(){{ age=18; name=“李明”; }};

这样就 不 用 写 p. name,p.age,方便一点
这样可以针对没有相应构造函数,但又要赋值
注意双括号

3.3 实例初始化与静态初始化

实例初始化(Instance Initializers)
在类中直接写
{ 语句…. }
实例初始化,先于构造方法{}中的语句执行(先于this或super之外的那些语句)
尽量少用这种{},有点怪怪的感觉。。

静态初始化(Static Initializers)
static { 语句…. } 只是与类有关的而不是跟实例有关的
静态初始化,在第一次使用这个类时要执行,
但其执行的具体时机是不确定的
但是可以肯定的是:总是先于实例的初始化

例子:

class InitialTest
{public static void main(String[] args) {new InitialTest2(6);}int n=10;  //step2{n++;System.out.println("InitialTest..."+n);}static int x;static {x++;System.out.println("static..." +x);}}class examp extends InitialTest{examp(int a){ this.a=a; System.out.println("this.a=" + a );}int a;//实例初始化的语句{System.out.println("InitialTest2..."+this.a);}static//这个初始化要先于实例的初始化{x++;System.out.println("static2..." +x);}
}
//输出:
//static...1
//static...1
//static2...2
//InitialTest...11
//InitialTest2...0
//this.a=6

3.4 构造方法的执行过程

构造方法的执行过程遵照以下步骤:
调用本类或父类的构造方法,直至最高一层(Object)
按照声明顺序执行字段的初始化赋值
执行构造函数中的其它各语句(不包括this或super)
简单地说:
先父类构造,再本类成员赋值,最后执行构造方法中的语句。

例子:


class JavaPConstructor
{int a=2000;JavaPConstructor(){this.a=3000;}
}

下面我们看一下反汇编后的结果

Compiled from "JavaPConstructor.java"
class text3.JavaPConstructor {int a;text3.JavaPConstructor();Code:0: aload_01: invokespecial #10                 // Method java/lang/Object."<init>":()V4: aload_05: sipush        20008: putfield      #12                 // Field a:I11: aload_012: sipush        300015: putfield      #12                 // Field a:I18: return
}

可见,它先调用了object方法,虽然没有写super,但实际上他会调用super。第二步把两千赋值到字段里面。(执行实例初始化及对字段的赋值)第三步才执行构造方法里面的语句

例子:(这次有super有this)

class ConstructS
{public static void main(String[] args){ Person p = new Student("李明", 18, "北大");}
}class Person
{String name="未命名";  //step 2int age=-1;Person( String name, int age ){super(); //step 1//step 3System.out.println( "开始构造Person(),此时this.name="+this.name+",this.age="+this.age );this.name=name; this.age=age; System.out.println( "Person()构造完成,此时this.name="+this.name+",this.age="+this.age );}
}class Student extends Person
{String school="未定学校"; //step2 Student( String name, int age, String school ){super( name, age );  //step 1看似一步其实包含父类三步//step 3System.out.println( "开始构造Student(),此时this.name="+this.name+",this.age="+this.age+",this.school="+this.school );this.school = school;System.out.println( "Student()构造完成,此时this.name="+this.name+",this.age="+this.age+",this.school="+this.school );}
}
//输出结果:
//开始构造Person(),此时this.name=未命名,this.age=-1
//Person()构造完成,此时this.name=李明,this.age=18
//开始构造Student(),此时this.name=李明,this.age=18,this.school=未定学校
//Student()构造完成,此时this.name=李明,this.age=18,this.school=北大

构造方法内部调用别的的方法
如果这个方法是虚方法,结果如何?
从语法上来说这是合法的,但有时会造成事实上的不合

class ConstructorInvokeVirtual
{public static void main(String[] args){ Person p = new Student("Li Ming", 18, "PKU");}
}class Person
{String name="未命名"; int age=-1;Person( String name, int age ){this.name=name; this.age=age; sayHello();}void sayHello(){System.out.println( "A Person, name: " + name + ", age: "+ age );}
}class Student extends Person
{String school="未定学校";Student( String name, int age, String school ){super( name, age );this.school = school;//赋值这是第三步才执行的}void sayHello(){//子类覆盖了父类的sayhello,父类就会一下跳到子类,但是此时还没有赋值好System.out.println( "A Student, name:" + name + ", age: "+ age + ", school: " + school );}
}

在本例中,在构造方法中调用了一个动态绑定的方法sayHello(),这时, 会使用那个方法被覆盖的定义,而这时对象尝未完全构建好,所以 School还没有赋值。
在构造方法中尽量避免调用任何方法,尽可能简单地使对象进入就绪 状态
惟一能够安全调用的是final的方法。这就不会有虚方法的问题

4 . 对象清除与垃圾回收

我们知道:new创建对象 那么如何销毁对象?
Java中是自动清除 不需要使用delete

4.1 对象的自动清除

垃圾回收(garbage collection )
对象回收是由 Java虚拟机的垃圾回收线程来完成的。
为什么系统知道对象是否为垃圾
任何对象都有一个引用计数器,当其值为0时,说明该对象可以回收
(任何对象我们要用它,它都是一个引用)(如果对象实体空间没有被任何引用所引用,那么其值为零)
引用计数示意(可见他是自动的)

 String method(){ String a,b; a=new String(“hello world”); b=new String(“game over”); System.out.println(a+b+”Ok”); a=null; //hello world 没被引用a=b; //game over有两个引用return a; }//结束了,引用都没了,但是如果调用了这个函数,又有引用了

System.gc ()方法

System.gc()方法
它是System类的static方法
它可以要求系统进行垃圾回收
但它仅仅只是”建议(suggest)”
你没法强制,只是希望虚拟机有空有条件时候进行垃圾回收

finalize() 方法

Java中没有“析构方法(destructor)”
但Object的finalize() 有类似功能
系统在回收时会自动调用对象的finalize() 方法。
protected void finalize() throws Throwable{}
子类的finalize()方法
可以在子类的finalize()方法释放系统资源
**一般来说,子类的finalize()方法中应该调用父类的finalize()方法,**以保证父 类的清理工作能够正常进行。

try -with-resources

由于finalize()方法的调用时机并不确定,所以一般不用finalize()
关闭打开的文件、清除一些非内存资源等工作需要进行处理
可以使用try-with-resources语句(JDK1.7以上)
对于实现了java.lang.AutoCloseable的对象

 try( Scanner scanner= new Scanner( … ) ){ 。。。。。。 }

会自动调用其close()方法,相当于,不管你try里面正常异常都会做下面的事情

  finally{ Scanner.close(); }

5 . 内部类与匿名类

定义

内部类( inner class )是在其他类中的类 (其他的类中再定义类)
匿名类( anonymous class)是一种特殊的内部类,它没有类名。

内部类(Inner class)

内部类的定义
将类的定义class xxxx{…}置入一个类的内部即可
编译器生成xxxx$xxxx这样的class文件
内部类不能够与外部类同名

内部类的使用
在封装它的类的内部使用内部类,与普通类的使用方式相同
在其他地方使用
类名前要冠以外部类的名字。
在用new创建内部类实例时,也要在 new前面冠以对象变量。
外部对象名.new 内部类名(参数)
例子:

class TestInnerClass{public static void main( String[] args ){Parcel p = new Parcel();p.testShip();Parcel.Contents c = p.new Contents(33);//前面要加上外部类的类名Parcel.Destination d = p.new Destination( "Hawii" );p.setProperty( c, d );p.ship();}
}class Parcel {private Contents c;private Destination d;class Contents {private int i;Contents( int i ){ this.i = i; }int value() { return i; }}class Destination {private String label;Destination(String whereTo) {label = whereTo;}String readLabel() { return label; }}void setProperty( Contents c, Destination d ){this.c =c; this.d = d;}void ship(){System.out.println( "move "+ c.value() +" to "+ d.readLabel() );}public void testShip() {c = new Contents(22);d = new Destination("Beijing");ship();}
}

在内部类中使用外部类的成员
内部类中可以直接访问外部类的字段及方法
即使private也可以
如果内部类中有与外部类同名的字段或方法,则可以用
外部类名.this.字段及方法
(平时用this都是指当前的,但是你这个指的是外部的字段及方法)
例子:

public class TestInnerThis
{    public static void main(String args[]){A a = new A();A.B b = a.new B();b.mb(333); }
}class A
{private int s = 111;public class B {private int s = 222;public void mb(int s) {System.out.println(s); // 局部变量sSystem.out.println(this.s); // 内部类对象的属性sSystem.out.println(A.this.s); //  外层类对象属性s}}
}//333
//222
//111

内部类的修饰符
内部类与类中的字段、方法一样是外部类的成员,它的前面也可以有 访问控制符和其他修饰符。
访问控制符:public,protected,默认(没有修饰符)及private
注:外部类只能够使用public修饰或者默认 (package)
final,abstract(表示他是不可继承的)

static 修饰符
用static修饰内部类 表明该内部类实际是一种外部类 (对象.new就不用了)
因为它与外部类的实例无关
有人认为static的类是嵌套类(nested class),不是内部类inner class
static类在使用时:
1、实例化static类时,在 new前面不需要用对象实例变量; (因为他和实例无关)
2、static类中不能访问其外部类的非static的字段及方法,既只能够访问static成员。
3、static方法中不能访问非static的域及方法,也不能够不带前缀地new 一个非 static的内部类。
例子:

class TestInnerStatic
{public static void main(String[] args) {A.B a_b = new A().new B();  // okA a = new A();A.B ab =  a.new B();Outer.Inner oi = new Outer.Inner();//Outer.Inner oi2 = Outer.new Inner();  //!!!error   //Outer.Inner oi3 = new Outer().new Inner(); //!!! error}
}class A
{private int x;void m(){new B();}static void sm(){//new B();  // error!!!!}class B{B(){ x=5; }}
}class Outer
{static class Inner{}
}

局部类

在一个方法中也可以定义类,这种类称为”方法中的内部类”
或者叫局部类(local class)
例子:

class TestInnerInMethod
{public static void main(String[] args) {Object obj = new Outer().makeTheInner(47);System.out.println("Hello World!" + obj.toString() );}
}class Outer
{private int size = 5;public Object makeTheInner( int localVar )//普通的方法{final int finalLocalVar = 99;class Inner  {//这就是局部类public String toString() {return ( " InnerSize: " + size + //可以访问外部类的成员// " localVar: " + localVar +   // Error! 不能访问内部普通的变量" finalLocalVar: " + finalLocalVar//可以访问该方法的final局部变量);}}return new Inner();}
}
//Hello World! InnerSize: 5 finalLocalVar: 99

使用局部类
1、同局部变量一样,方法中的内部类
不能够用 public,private,protected,static修饰,(不能修饰局部变量同类也不能修饰局部类) 但可以被final(不可继承)或者abstract(抽象)修饰。
2、可以访问其外部类的成员
3、不能够访问该方法的局部变量,(它是随时产生随时消失的,进到方法里就有,退出就消失了,是不可捉摸的不可访问的)除非是final局部变量

匿名类

匿名类( anonymous class)是一种特殊的内部类
它没有类名,在定义类的同时就生成该对象的一个实例
“一次性使用”的类(所以没必要给他个名字)
(一般他是扩展一个或者说要继承一个类,实现一个接口)
例子:

class TestInnerAnonymous
{public static void main(String[] args) {Object obj = new Outer().makeTheInner(47);System.out.println("Hello World!" + obj.toString() );}
}class Outer
{private int size = 5;public Object makeTheInner( int localVar ){final int finalLocalVar = 99;return new Object()  {//这个类没取名字,但是总得要写,所以他写它父类的名字//或者它实现接口的名字public String toString() {return ( " InnerSize: " + size + " finalLocalVar: " + finalLocalVar);}};//实际上是方法体里面的类的简写,把new这个对象以及定义这个对象一起写}
}
//Hello World! InnerSize: 5 finalLocalVar: 99

匿名 类的使用
1、不取名字,直接用其父类或接口的名字
也就是说,该类是父类的子类,或者实现了一个接口
编译器生成 xxxxx$1之类的名字
2、类的定义的同时就创建实例,即类的定义前面有一个new
new 类名或接口名(){……}
不使用关键词class,也不使用extends及implements。直接写父类的名字就完事
3、在构造对象时使用父类构造方法
不能够定义构造方法,因为它没有名字
如果new对象时,要带参数,则使用父类的构造方法

匿名 类的应用
用到界面的事件处理 (继承一个类)
注册一个事件侦听器

示例 AutoScore.java 中 //SymAction lSymAction = new SymAction(); //btnNew.addActionListener(lSymAction);btnNew.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent event) { btnNew_ActionPerformed(event); } });

作为方法的参数
排序,给一个比较大小的接口

如 SortTest.java
Arrays.<Book>sort( books, new Comparator<Book>(){
//需要一个接口去比较这两本书
public int compare(Book b1, Book b2){ return b1.getPrice()-b2.getPrice();
}
});

6 . Lambda表达式

Lambda表达式是从Java8增加的新语法
Lambda表达式(λ expression)的基本写法
(参数)->结果
如 (String s) -> s.length()
如 x->x*x
如 () -> { System.out.println(“aaa”); }
大体上相当于其他语言的“匿名函数”或“函数指针”
在Java中它实际上是“ 匿名类的一个实例
例子:

class LambdaRunnable  {public static void main(String argv[]) {Runnable doIt =  new Runnable(){public void run(){ System.out.println("aaa");}};new Thread( doIt ).start();Runnable doIt2 = ()->System.out.println("bbb");//简洁new Thread( doIt2 ).start();new Thread( ()->System.out.println("ccc") ).start();//作为线程的一个参数更简洁}
}

可以看出
Lambda表达式是接口或者说是接口函数的简写
其基本写法是参数->结果
这里,参数是()或1个参数或 (多个参数)
结果是指 表达式 或 语句 或 {语句}

例子:

@FunctionalInterface
interface Fun { double fun( double x );}public class LambdaIntegral
{public static void main(String[] args){double d = Integral( new Fun(){public double fun(double x){ return Math.sin(x); }}, 0, Math.PI, 1e-5 );//简写d = Integral( x->Math.sin(x),0, Math.PI, 1e-5 );System.out.println( d );d = Integral( x->x*x, 0, 1, 1e-5 );System.out.println( d );}static double Integral(Fun f, double a, double b, double eps)// 积分计算{int n,k;double fa,fb,h,t1,p,s,x,t=0;fa=f.fun(a); fb=f.fun(b);n=1; h=b-a;t1=h*(fa+fb)/2.0;p=Double.MAX_VALUE;while (p>=eps){ s=0.0;for (k=0;k<=n-1;k++){ x=a+(k+0.5)*h;s=s+f.fun(x);}t=(t1+h*s)/2.0;p=Math.abs(t1-t);t1=t; n=n+n; h=h/2.0;}return t;}}

Lambda大大地简化了书写
在线程的例子中
new Thread( ()->{ … } ).start();
在积分的例子中
d = Integral( x->Math.sin(x), 0, 1, EPS );
d = Integral( x->x*x, 0, 1, EPS );
d = Integral( x->1, 0, 1, EPS );
在按钮事件处理中
btn.addActionListener( e->{ … } ) );

能写成 Lambda的接口的条件
由于Lambda只能表示一个函数,所以
能写成Lambda的接口要求包含且最多只能有一个抽象函数
这样的接口可以(但不强求)用注记
@FunctionalInterface 来表示。称为函数式接口

@FunctionalInterface
interface Fun { double fun( double x );}

再举一例:排序

Comparator<Person> compareAge = (p1, p2) -> p1.age-p2.age;
Arrays.sort(people, compareAge);
Arrays.sort(people, (p1, p2) -> p1.age-p2.age);
Arrays.sort(people, (p1, p2) -> (int)(p1.score-p2.score));
Arrays.sort(people, (p1, p2) -> p1.name.compareTo(p2.name));
Arrays.sort(people, (p1, p2) -> -p1.name.compareTo(p2.name));

Lambda表达式,不仅仅是简写了代码,
更重要的是:
它将代码也当成数据来处理
函数式编程

7 . 装箱、枚举、注解

基本类型的包装类

基本类型的包装类
它将基本类型(primitive type) 包装成Object(引用类型)(因为基本类型没法当对象用)
如int->Interger
共8类:
Boolean, Byte, Short, Character, Integer, Long, Float, Double
Integer I = new Integer(10);

装箱与拆箱

装箱(Boxing) Integer I = 10;
拆箱(Unboxing) int i = I;
实际译为
Integer I= Integer.valueOf(10);
int i = I.intValue();
主要方便用于集合中,如: Object [] ary = { 1, “aaa”};

枚举

枚举(enum)是一种特殊的class类型
在简单的情况下,用法与其他语言的enum相似
enum Light { Red, Yellow, Green };
Light light = Light.Red;
但实际上,它生成了 class Light extends java.lang.Enum

自定义枚举
可以在enum定义体中,添加字段、方法、构造方法

  enum Direction { EAST("东",1), SOUTH("南",2), WEST("西",3), NORTH("北",4); private Direction(String desc, int num){ this.desc=desc; this.num=num; } private String desc; private int num; public String getDesc(){ return desc; } public int getNum(){ return num; } }

注解

注解(annotation)
又称为注记、标记、标注、注释(不同于comments)
是在各种语法要素上加上附加信息,以供编译器或其他程序使用
所有的注解都是 java.lang.annotation. Annotation 的子类

常用的注解,如
@Override 表示覆盖父类的方法
@Deprecated 表示过时的方法
@SuppressWarnings 表示让编译器不产生警告
自定义注解,比较复杂
public @interface Author {
String name();
}

8 . 没有指针的Java语言

引用(reference)实质就是指针(pointer)
但是它是受控的、安全的
比如
会检查空指引
没有指针运算 *(p+5)
不能访问没有引用到的内存
自动回收垃圾

C 语言指针在Java中的体现
(1)传地址 ->对象
引用类型,引用本身就相当于指针
可以用来修改对象的属性、调用对象的方法
基本类型:没用对应的
如交换两个整数
void swap(int x, int y){ int t=x; x=y; y=t; }
int a=8, b=9; swap(a.b);
一种变通的办法,传出一个有两个分量x,y的对象
(2)指针运算 -> 数组
*(p+5) 则可以用 args[5]
(3)函数指针 -> 接口、Lambda表达式
例:求积分,线程 、回调函数、事件处理

(4)指向结点的指针-> 对象的引用
class Node {
Object data;
Node next;
}

(5)使用JNI
Java Native Interface(JNI)
它允许Java代码和其他语言写的代码进行交互

java中相等还是不等

基本 类型的相等

数值类型:转换后比较
浮点数,最好不直接用==
Double.NAN==Double.NAN 结果为false
请参见JDK的API文档
boolean型无法与int相比较

装箱 对象是否相等

 Integer i = new Integer(10); Integer j = new Integer(10); System.out.println(i==j);  //false,因为对象是两个Integer m = 10; Integer n = 10; System.out.println(m==n); //true,因为对象有缓存Integer p = 200; Integer q = 200; System.out.println(p==q); //false,因为对象是两个,不能超过-128到+127

注意缓存
If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

枚举、引用对象是否相等
枚举类型
内部进行了惟一实例化,所以可以直接判断
引用对象
是直接看两个引用是否一样
如果要判断内容是否一样,则要重写equals方法
如果重写equals方法,则最好重写 hashCode()方法

String 对象的特殊性
String对象
判断相等,一定不要用==,要用equals
但是字符串常量( String literal)及字符串常量会进行内部化(interned), 相同的字符串常量是 = =的

例子:

String hello = "Hello", lo = "lo"; System.out.println( hello == "Hello");  //true System.out.println( Other.hello == hello ); //true
System.out.println( hello == ("Hel"+"lo") ); //true
System.out.println( hello == ("Hel"+lo) ); //false
System.out.println( hello == new String("Hello")); //false
System.out.println( hello == ("Hel"+lo).intern()); //true

Java一些基础知识的整合相关推荐

  1. java类与接口思维导图_详解java接口基础知识附思维导图

    接口: 官方的含义是---->java接口是一系列方法的声明,是一些方法特征的集合 疑问: 那为什么不用抽象类呢?把他们共有的方法集合起来放在一个抽象类里面,同样可以调用哇,但是反过来想一想如果 ...

  2. Java进阶基础知识

    Java进阶基础知识 1.Java 基础 Java类设计的原则就是内聚性,一致性和封装性是Java设计的基本原则 1.1 Java基础理论 Java基础理论知识 1.2继承的优缺点 1.2.1优点 : ...

  3. java培训基础知识都学哪些

    很多人都开始学习java技术,觉得java语言在未来的发展前景空间非常大,事实却是如此,那么针对于零基础的同学, 学习java技术需要学哪些呢?下面我们就来看看java培训基础知识都学哪些? java ...

  4. 你觉得什么才是 Java 的基础知识?

    近日里,很多人邀请我回答各种j2ee开发的初级问题,我无一都强调java初学者要先扎实自己的基础知识,那什么才是java的基础知识?又怎么样才算掌握了java的基础知识呢?这个问题还真值得仔细思考. ...

  5. 计算机java语言教程,计算机JAVA教程二讲Java语言基础知识.doc

    计算机JAVA教程二讲Java语言基础知识 2.1简单数据类型 2.1.1 标识符和保留字 1.标识符 程序员对程序中的各个元素加以命名时使用的命名记号称为标识符(identifier).Java语言 ...

  6. java ee基础知识_Java EE:基础知识

    java ee基础知识 想要了解一些基本原则,即与Java EE相关的技术术语. 对于许多人来说,Java EE / J2EE仍然最多意味着Servlet,JSP或Struts. 没有冒犯或双关语! ...

  7. hashcode是什么意思_什么才是 Java 的基础知识?

    作者:晓风轻 链接:zhuanlan.zhihu.com/p/28615617 近日里,很多人邀请我回答各种j2ee开发的初级问题,我无一都强调java初学者要先扎实自己的基础知识,那什么才是java ...

  8. JAVA NIO基础知识

    本文来说下JAVA NIO基础知识. 文章目录 NIO概述 NIO简介 NIO的特性/NIO与IO区别 读数据和写数据方式: NIO核心组件简单介绍 Java NIO 之 Buffer(缓冲区) Bu ...

  9. java 反射基础知识

    java 反射 基础知识 反射:reflection 反射关键类 java 反射部分应用 反射:reflection 在运行中分析类. 在运行中查看和操作对象. 基于反射自己创建对象. 调用不可以访问 ...

最新文章

  1. P2048 [NOI2010]超级钢琴
  2. java.nio.ByteBuffer用法小结
  3. VS2008 JS调试和Silverlight 后台代码调试 相互影响的问题。---自己做实例证明
  4. 20171113_Python学习五周一次课
  5. 开发人员学Linux(13):CentOS7安装配置IT设备监控系统Zabbix
  6. 0-5v转0-20ma和0-5v转4-20ma
  7. 基于天然概率的无需人为平衡的skiplist的美之展现
  8. 用matlab读pcap文件,libpcap读取本地pcap文件
  9. 2×3卡方检验prism_SPSS之卡方检验
  10. 思维导向树6级节点_8种常见的思维导图类型
  11. python卷积神经网络预测股价_解读:一种基于CNN-LSTM混合神经网络的股价预测模型...
  12. Quartz入门教程
  13. Python 为图片和 PDF 上去掉水印,超简单快来学!
  14. 《scrum要素》读书笔记工作总结
  15. 读书笔记-->《精益数据分析》第二部分 | 第15章:创业阶段2——黏性
  16. windows修改默认端口3389
  17. map_server地图保存
  18. 记录——超声相控阵,斜入射;大道理(取自主论文)
  19. 西计算机科学和电子科学与技术的区别,“电子信息科学与技术”和“电子科学与技术”专业的区别...
  20. [双语阅读]美国历届总统大排名 林肯夺冠

热门文章

  1. struts处理中文乱码问题总结
  2. C语言入门基础——Brute-Force算法
  3. PyQt5代码触发QTreeWidget的列表中某个item点击信号
  4. 计算机组成原理和体系结构----软考(到处copy)
  5. cdgb调试linux崩溃程序
  6. 将当前的head推送到远程_Git 通俗易懂系列 三、远程仓库和标签
  7. oracle删除唯一索引sql语句_高级SQL之在选择语句中使用更新和删除
  8. python替换txt指定内容_python 实现类似sed命令的文件内容替换
  9. 为什么用python写爬虫_零基础,是怎么开始写Python爬虫的
  10. 忘记mysql数据库名称_忘记MySQL数据库密码的解决办法