Java一些基础知识的整合

文章目录

    • 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++里的友元,十分方便

同一个类中同一个包中不同包中的子类不同包中的非子类
privateYES
默认 (包可访问)YESYES
protectedYESYESYES
publicYESYESYESYES

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最终的、不可改变的YesYesYes
abstract抽象的、不可实例化的YesYes

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/560309.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

空军部队计算机专业有没有用武之地,报名当兵可以选择陆军、海军、空军、武警、火箭军,艰苦地区部队...

如果是本科生&#xff0c;在部队表现优异&#xff0c;年龄不超26周岁是可以被推荐去参加大学生士兵提干考试。考上之后需要到军校培训6个月左右&#xff0c;毕业后下部队就是中尉军衔。二、报名当兵时有陆军、海军、空军、武警、火箭军&#xff0c;艰苦地区部队&#xff0c;选择…

查看本地计算机ip命令,查看你本机的IP信息的命令ipconfig详解【图】

原标题&#xff1a;"查看你本机的IP信息的命令ipconfig详解【图】"关于路由器的知识分享。 - 素材来源网络 编辑:kaka。对于ipconfig命令大家应该不陌生&#xff0c;它主要用于显示本地计算机网络适配器的ip地址、子网掩码以及默认网关等信息。1、IPconfig不带参数不…

什么是传感器? 传感器由哪几部分组成? 传感器分类?

文章目录1.什么是传感器&#xff1f;2.传感器由哪几部分组成&#xff1f;3.传感器分类&#xff1f;1.什么是传感器&#xff1f; 传感器&#xff08;英文名称&#xff1a;transducer/sensor&#xff09;是一种检测装置&#xff0c;能感受到被测量的信息&#xff0c;并能将感受到…

计算机win7关机重启,电脑win7关机后自动重启如何解决_win7一关机就立马自动重启修复方法-win7之家...

我们在使用完win7系统电脑之后&#xff0c;都会顺手对其进行关机操作&#xff0c;以此防止电脑中的硬件过度消耗&#xff0c;可是近日有些用户在将win7电脑关机之后却又出现了重启的情况&#xff0c;最终不得不以切断电源的方式来解决&#xff0c;那么电脑win7关机后自动重启如…

RFID 射频 RFID工作流程 自动识别技术 工作频段 短距离无线通信技术

文章目录1.rfid概念&#xff1a;2.射频概念&#xff1a;3.rfid工作流程&#xff1a;4.几类自动识别技术各有什么特点&#xff1f;他们有何不同。5.RFID系统有哪些工作频段&#xff1f;各频段的特点是什么。6.对比几种短距离无线通信技术1.rfid概念&#xff1a; RFID是一种自动…

链表 队列 基本概念 为什么使用二叉查找树 抽象数据类型

文章目录0.抽象数据类型(ADT)的优点&#xff1f;1.为什么需要链表&#xff1f;2.链表的概念&#xff1f;3.队列的概念&#xff1f;4.为什么需要二叉查找树&#xff1f;0.抽象数据类型(ADT)的优点&#xff1f; ADT版本可读性高&#xff0c;隐藏编程细节&#xff0c;对终端用户隐…

黑盒测试还适用于测试软件,软件测试 黑盒测试中的决策表技术

决策表技术是用于黑盒测试的广泛使用的用例设计技术之一。这是一种系统方法&#xff0c;它以表格形式捕获各种输入组合及其各自的系统行为。它也称为因果表。该技术用于系统地选择测试用例; 它节省了测试时间&#xff0c;并为软件应用程序的测试区域提供了良好的覆盖。决策表技…

统计一行文本的单词个数

统计一行文本的单词个数 习题6-8 统计一行文本的单词个数 (15 分) 本题目要求编写程序统计一行字符中单词的个数。所谓“单词”是指连续不含空格的字符串&#xff0c;各单词之间用空格分隔&#xff0c;空格数可以是多个。 输入格式: 输入给出一行字符。 输出格式: 在一行中输…

戴尔计算机windows未能启动,戴尔电脑windows7无法启动安装过程怎么办

windows7无法启动安装过程怎么办&#xff1f;暗黄win7系统的时候经常遇见这种问题可能是硬件问题导致的&#xff0c;还有可能是系统设置问题导致的&#xff0c;我们具体原因具体分析&#xff0c;一起来看看解决方法&#xff0c;动手实践起来吧&#xff01;1、方法一&#xff1a…

c语言 数据结构 list、queue、tree抽象数据类型的定义与实现 详尽代码和注释

本文使用c语言定义并实现list、queue、tree抽象数据类型&#xff0c;代码有详尽注释&#xff0c;可以通过代码熟悉原理并运用数据结构。 0.ADT基础知识 类型包括两类信息&#xff0c;属性和操作。在编程时&#xff0c;根据编程问题匹配合适的数据类型。 定义一个新的数据类型…

局域网服务器没显示,无法登录服务器 局域网也不显示连接

什么情况啊 论坛上很多这种情况 客服快来远程帮我解决一下&#xff01;&#xff01;&#xff01;&#xff01;********************************************************************************[星际争霸重置版]客户端到服务器Ping测试&#xff1a;服务器&#xff0c;223.25…

css 回到首页按钮,js+css实现回到顶部按钮(back to top)

本文实例介绍了jscss实现回到顶部按钮的方法&#xff0c;分享给大家供大家参考&#xff0c;具体内容如下效果htmlcssp#back-to-top{position:fixed;bottom:100px;right:80px;}p#back-to-top a{text-align:center;text-decoration:none;color:#d1d1d1;display:block;width:30px;…

Java Set基础知识

Set集合中不包含重复对象。 HashSet&#xff1a; HashSet的底层用哈希散列表来存储对象。其中的散列码是由关键字的信息内容确定的。关键字到散列码的转换是自动执行的。 存储元素时底层要做的判断:1.调用元素的hashCode()方法,直接访问对应的数组元素,有没有这个哈希值,没有就…

c语言基础练习题 字符串输入scanf/gets 字符串赋值、比大小

PTA上C语言程序设计练习题&#xff0c;包含查找书籍、字符串排序。主要用到字符串输入scanf/gets 字符串赋值、比大小等知识。 1.查找书籍 习题9-4 查找书籍 (20 分) 给定n本书的名称和定价&#xff0c;本题要求编写程序&#xff0c;查找并输出其中定价最高和最低的书的名称和…

ajax搜索思路,jquery创建一个ajax关键词数据搜索实现思路

在web开发过程当中&#xff0c;我们经常需要在前台页面输入关键词进行数据的搜索&#xff0c;我们通常使用的搜索方式是将搜索结果用另一个页面显示&#xff0c;这样的方式对于搭建高性能网站来说不是最合适的&#xff0c;今天给大家分享一下如何使用 jquery&#xff0c;MySQL …

esxi 修改服务器配置失败,R720服务器安装 ESXI 5.5update1后出现XXX错误

R720服务器&#xff0c;安装ESXI5.5UPDATE1 (DELL 的版本)后&#xff0c;安装了几个WIN2003及CENTOS的虚拟机。启用了一台2003和一台CENTOS6.5没有安装vCenter Server从vSphere Client端连接到esxi5.5服务器&#xff0c;发现每次重新启动ESXI&#xff0c;启动事件里面有很多类似…

(哈希)两数之和(leetcode 1)

1.题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意…

丢失的数字

给定一个包含 [0, n] 中 n 个数的数组 nums &#xff0c;找出 [0, n] 这个范围内没有出现在数组中的那个数。 示例 1&#xff1a; 输入&#xff1a;nums [3,0,1] 输出&#xff1a;2 解释&#xff1a;n 3&#xff0c;因为有 3 个数字&#xff0c;所以所有的数字都在范围 [0,3…

ftp服务器收集文件,ftp服务器收集文件

ftp服务器收集文件 内容精选换一换为了对源端服务器进行迁移可行性评估以及为后续目的端服务器的选择和配置提供必要性数据&#xff0c;迁移Agent会收集源端服务器的相关信息并上报到主机迁移服务。收集的Windows操作系统的具体数据如表1所示。收集的Linux操作系统的具体数据如…

STM32-GPIO学习-跑马灯实验和按键实验-寄存器版本和HAL库版本

一、stm32跑马灯实验 a.GPIO general purpose input output 通用输入输出端口&#xff0c;可以做输入也可做输出&#xff0c;GPIO端口可通过程序配置成输入或输出。 STM32FXXXIGT6一共9组IO&#xff1a;PA~ PI&#xff0c;其中PA~ PH每组16个IO&#xff0c;PI只有PI0~PI11。…