堆,栈,常量池
栈:存放基本类型的数据和对象的引用(定义名),但对象本身不存放在栈中,而是存放在堆中
堆:存放用
new
产生的数据静态域:存放在对象中用
static
定义的静态成员常量池:存放常量,如没用
new
生成的字符串
等号==
==与equals方法(A.equals(B)
)
equals方法:A,B不是对象类型,则是值判断,:如果A,B都是对象,则是对象判断!!!
==:
如果两边都是数据类型,则根据值判断,包括
int
与flaot
的判断如果两边都是对象类型,则判断是否指向同一对象
如果一个数据类型,一个对象,则是值判断
如果是对象属性,则是值判断
注释
单行注释(
// 注释文字
)多行注释(
/* *注释文字 **/
)文档注释(
/** **注释文档 \*/
)JAVA特有(通过Javadoc 生成 API 帮助文档, API 文档相当于产品说明书)
文档注释:主要用来说明类、成员变量和方法的功能
与其他的区别:非java Doc注释给写代码维护代码的人看的
字符串
String
支持 ‘+’ 实现字符串拼接(char的‘+’是ac码的相加)
String
创建数组定义数组大小会报错
数据类型
布尔型关键字:boolean
java支持数据类型自动转换:
允许把一个数值直接量直接赋给另一种类型的变量
String
类型的直接量不能赋给其他类型的变量boolean
类型的直接量只能赋给boolean
类型的变量String
转int
:Integer.parseInt(str)
char
转string
:str = ch + ""
键盘输入
import java.util.Scanner; //1.引入输入包
public class mytest {
public static void main(String[] args) {
Scanner myScanner = new Scanner(System.in); //2.创建输入对象
String name = myScanner.next(); //3.1对象的next方法获取字符串
int age = myScanner.nextInt(); //3.2对象的nextInt方法获取整型数据
}
}
数组
默认放到堆中
推荐命名方式:
type[] arrayName; // 数据类型[] 数组名;
//声明数组大小
arrayName = new type[size]; // 数组名 = new 数据类型[数组长度];
在声明数组时不需要规定数组的长度,例如:
int score[10]; // 这是错误的
int[] a = new int[5]; //对
int[] number = new int [5] {1,2,3,4,5}; //错,不能即指定数组的长度,又为每个数组元素分配初始值
支持数组赋值给数组:
int[] a = {1, 2, 3};
System.out.println(a[1]); //输出2
int[] b = a;
b[1] = 100;
System.out.println(a[1]); //输出100
System.out.println(b[1]); //输出100
注意:数组赋值给数组是以指针形式来赋值
对象
对象分配机制
Cat mycat1 = new Cat(); //创建mycat1指针指向堆的一空间
mycat1.name = "inin";
Cat mycat2 = mycat1; //mycat2指针指向mycat1的指向,mycat2.name为inin
##重载
定义:同一个类中包含了两个或两个以上方法名相同的方法,但形参列表不同,这种情况被称为方法重载
形参列表不同指个数或类型不同或个数类型都相同但顺序不同,返回类型不同不算重载
##方法
可变参数:
public int sum(int... nums) { //nums相当于未指向的数组指针,接收到数据后创建空间创建数组
System.out.println(nums.length); //内置length方法求数组大小
}
//与普通参数一起使用
public int sum(int a, int... nums) {
//可变参数必须在最后
}
构造方法(构造器):用来初始化对象实例,一般接着写在类定义的属性后面
public static void main(String args[]) {
Person p1 = new Person("inin", 30);
System.out.println(p1.name); //输出inin
System.out.println(p1.age); //输出30
}
class Person {
String name;
int age;
public Person(String pName, int pAge) {
name = pName;
age = pAge;
}
}
备注:无返回,不能写void
;方法名和类名相同
this
关键字:
作用:最大的作用就是让类中一个方法,访问该类里的另一个方法或实例变量
备注:可以访问构造器
this(参数列表); //只在构造器里面使用,来使用另一个构造器
包
定义:将处理同一方面的问题的类放在同一个目录下,以便于管理
作用:
区分相同名称的类。
能够较好地管理大量的类。
控制访问范围。
package
关键字:声明当前类所在的包,放在类的最上面,只允许只有一个
注意:不同的java文件包名相同表示这些java文件里的类都归属于同一个包,
import
关键字:导入指定包层次下的某个类或全部类
import example.Test; //导入example包的Test类
import example.*; //导入example包所有类
常用的包:
java.lang.*
//基本包,默认引入java.util.*
//系统提供的工具包,含Scanner类java.net.*
//网络包,网络开发java.awt.*
//java的界面开发,GUI
访问修饰符
定义:限定类,方法,属性的访问权
作用:
防止对封装数据的未授权访问(即调用)。
有助于保证数据完整性。
当类的私有实现细节必须改变时,可以限制发生在整个应用程序中的“连锁反应”
类的访问控制符:只能是空(friendly
默认)或者 public
;
方法和属性的访问控制符: public
(公有)、 private
(私有)、protected
(保护) 和 friendly
(默认、空)
继承
1.子类不可以直接访问父类private
属性和方法,要通过父类的公共方法间接访问
2.子类自动调用父类构造器,完成父类的初始化,若父类没有无参构造器,则在子类的构造器中必须用super
指定父类的构造器来完成父类的初始化,确保父类被初始化
3.super
指定父类构造器,必须写在子类构造器的第一行
4.访问子类属性或方法,先看子类是否有相应的属性和方法,有就调用子类的,没有再向上一级父类访问,即当子类和父类有同名属性和方法时默认先调用子类的
5.子类无super
则默认调用父类的无参构造,有则不调用,而调用super
指定的构造
super
作用:访问父类的属性,方法,构造器
访问父类属性,方法:super.属性名;super.方法名
访问父类构造器:super
(参数列表)
//调用的查找顺序
funC(); //查找当前类的的方法,没有则向父类查找,直到object类
this.func(); //同上
super.func(); //直接向父类查找,直到object类
重写
定义:子类中创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,但方法体中的代码不同,以实现不同于父类的功能
注意:子类方法返回类型和父类方法的一样,或是父类方法返回的类型的子类,也算重写
class Far {
public Object func() {
return null;
}
}
class Son extends Far { //允许
public string func() { //Object类是string类的父类
return null;
}
}
注意:子类方法不能缩小父类方法的访问权限,若父类方法为public,子类方法不能为private等权限变小的
多态
多态存在的3个条件:继承,重写,父类引用指向子类(Parent p = new Child();
)
编译类型,运行类型:运行类型必为编译类型的子类
Animal a = new Dog(); //Animal为编译类型, Dog为运行类型
a = new Cat(); // 运行类型可以改变,但编译类型固定不变
a.func(); //先从子类Dog中查找方法,然后再向上查找
方法传参的类的多态:传参是指定类,也可以是指定类的子类
//方法
public void func(Animal animal, Food food) { //传入的类是Animal,也可以是Animal的子类Cat等
//输出animal的name,food的name
}
//调用
a.func(catB, riceC); //catB为Animal的子类Cat的实例对象,riceC为Food子类rice的实例对象
向上转型:父类引用指向子类:Parent p = new Child();
特点:p具有父类属性和方法,且具有子类的方法,但无子类的属性
注意:可以调用父类成员(遵守访问权限),但不能调用子类的属性,调用方法时会先从子类查找
注意:属性没有重写
instanceOf
关键字:判断a对象的运行类型是否为b类型或b类型的子类
System.out.println(a instanceOf b); //是运行类型,不是编译类型
动态绑定机制: 调用对象方法时,对象的所有方法都是从运行类型中开始找,甚至编译类型里的方法里的方法也是从运行类型中找。
多态数组: 符合动态绑定机制,new
谁,方法就调用谁
Person persons = new Person[3]; //对象数组
persons[0] = new Person();
persons[1] = new Student(); //向上转型
persons[2] = new Teacher(); //向上转型
persons[i].say(); //调用方法时,遵循动态绑定机制,即先从i类型中的方法找
Object类
equals()
:比较两个对象的内容是否相等
注意:==
运算符是两边是否指向同一实例(是否地址相同),判断new
生成的变量时与equals
方法有区别
static关键字
static
声明的变量或方法叫类变量,类方法,也称静态变量
static
修饰的成员变量和方法,从属于类普通变量和方法从属于对象
静态方法不能调用非静态成员,编译会报错,反之可以
静态方法不能用
this
和super
特点:
不依赖对象名访问,直接用 类名.类变量 或 类名.类方法 即可以调用
被所有对象共享,在内存中只有一个副本,在类初次加载的时候才会初始化
代码块
解析:构造器的补充
语法:
[修饰符] {
代码
};
修饰符可写可不写,只能写
static
有
static
的叫静态代码块,没有的叫普通代码块;可写可不写
先于构造器执行
静态代码块:随则类的加载而执行
普通代码块:创建对象执行,和类加载无关
如果只是调用类的静态成员,普通代码块不被调用
静态代码块与静态成员优先级相同,普通代码块与普通成员优先级相同
父类先于子类执行代码块
构造器最后执行
静态代码块只能调用静态成员,普通代码块任意调用
//子类继承关系时创建实例时调用顺序
1.父类静态代码块,静态成员
2.子类静态代码块,静态成员
3.父类普通代码块,==普通属性==初始化
4.父类的构造方法 //构造器后于普通属性
5.子类普通代码块,==普通属性==初始化
6.子类的构造方法 //构造器后于普通属性
类什么时候被加载:
new
实例创建子类实例,父类被加载
使用类的静态成员
final关键字
相当于const
,变量名一般全大写
//修饰类:表示当前类不能被继承
final class A {}
//修饰父类方法:此方法无法被子类覆盖/重写
final void func() {}
//修饰变量:相当于const
final int a = 100;
//修饰数组:表示数组地址不可改变,但值可以改变
final int[] a = {1, 2, 3};
抽象类abstract
关键字:abstract
作用:把子类大致相同的代码抽象出来成抽象类,但可以利用重写的方式让子类实现大致相同中的不同
//修饰类
访问修饰符 abstract 类名 {}
//修饰方法
访问修饰符 abstract 返回类型 方法名(参数) {}; //里面不能写代码
//子类继承了抽象类,必须重写抽象类的所有抽象方法
抽象类不能被实例
抽象类可以没有
abstract
方法方法有
abstract
,类必须声明为abstract
abstract
只能修饰类和方法,不能修饰属性和其他抽象类可以有任意成员
抽象方法不能写代码
一个类继承了抽象类,则它必须实现(重写)抽象类的所有抽象方法,除非它也声明为抽象类
抽象方法不能被
private
,final
,static
修饰,否则子类无法重写
接口Interface
解析:特殊的抽象类,关键字:Interface
、default
、implements
interface 接口名 { //创建接口
//属性
//方法:
//1.抽象方法
public void func(); //可以省略abstract关键字 相比于抽象类少了中括号
//2.默认实现方法 可以写代码字体
default public void func() { //default关键字
代码
}
//3.静态方法
public static void func() {
代码
}
}
//普通类实现接口
class 类名 implements 接口 {
//接口成员
//自己成员
//重写接口方法
}
//抽象类实现接口
abstract class 类名 implements 接口 {
//成员
//可以不用重写接口方法
}
//普通类实现多个接口
class 类名 implements 接口1, 接口2 {
//成员
//重写接口方法
}
//接口继承多个接口
interface A extends B,C {}
接口不能被实例化
类含有接口的成员
接口方法只能默认被
public abstract
修饰普通类实现接口,必须实现接口方法,抽象类则不用
接口中的属性,只能且默认
public static final
修饰,如int a = 10
(必须初始化)接口修饰符只能是
public
和默认
class A extends B implements C {} //A类继承B且实现C
//举例
interface A {
int x = 0; //默认静态
}
class B{
int x = 1;
}
class C extends B inplements A {
public void pX() {
//System.out.println(x); 错误
System.out.println(A.x + " " + super.x); //正确
}
public static void main(String[] args) {
new C().pX();
}
}
接口与继承比较:子类继承则自动拥有父类的功能,子类需要扩展则实现接口方式
理解:实现接口 是 对java 单继承机制的一种补充
接口的多态特性:
//接口名Usb,实现接口的类名Phone、Camera
Usb[] usbs = new Usb[2];
usbs[0] = new Phone(); //多态
usbs[1] = new Camera();
for(int i = 0; i < usbs.length; i ++) {
usbs[i].func(); //动态绑定
if(usbs[i] instanceof Phone) { //特有方法调用
((Phone)usbs[i].call);
}
}
类的5大成员:属性,方法,构造器,代码块,内部类
内部类
定义:在类内部的类
局部类
定义在类的局部位置里,如方法内,代码块
局部内部类(有类名)
class Outer {
private int n1 = 100;
private void func1() {}
public void func2() { //方法
final class Inner { //局部内部类
public void f2() {
int n1 = 333;
System.out.println(n1 + Outer.this.n1); //访问内部n1和外部n1
func1(); //访问外部成员
}
}
Inner m = new Inner(); //外部类使用局部类,需创建
m.f2();
}
}
通常定义在方法或代码块中,有类名
可以访问外部任意成员,包括私有
不能添加修饰符,但可以添加final
作用域:在定义的方法或代码块中,外部其他类不能访问
外部类使用局部内部类只能在作用域内使用
局部内部类与外部类成员重名时,调用遵循就近原则,可用
外部名.this.成员名
形式调用外部成员
匿名内部类(无类名)
实现接口或继承类 ,简单创建一个仅用一次的类
class Outer {
//匿名类实现接口:
IA tiger = new IA() { //内部会自动创建一个匿名类实现IA接口然后返回实例给tiger,然后匿名类被销毁
@Override
public void cry() { //该重写的还是要重写
//
}
}; //有分号
tiger.cry();
new IA(){
@Override
public void cry() { //该重写的还是要重写
//
}
}.cry; //也可以直接这样调用cry
//匿名类继承类
Father father = new Father("jack") { //并传参
};
}
class Father {
}
interface IA {
public void fun();
}
/*
class B implements A{} //以往需要写个类实现接口,然后再创建实例
//而匿名内部类在内部创建类并返回实例然后销毁,简化开发
*/
注意:tiger的编译类型为IA
,运行类型为已销毁的匿名类
可以访问外部任意成员,包括私有
作用域:在定义的方法或代码块中,外部其他类不能访问
外部类使用局部内部类只能在作用域内使用
局部内部类与外部类成员重名时,调用遵循就近原则,可用
外部名.this.成员名
形式调用外部成员
匿名内部类实践:
public class A {
public static void main(String[] args) {
f1(new IL() { //返回一个实现接口IL的类的实例
@Override
public void show() {
//
}
});
}
public static void f1(IL il) { //形参是接口IL,但传进去的是实现接口的匿名内部类
il.show();
}
}
interface IL {
public void show();
}
/*
传统方法
定义一个class p实现IL,再f1(new p)
*/
成员内部类
定义在外部类的除方法代码块的地方
class A {
class B {} //成员内部类
}
可以访问外部任意成员
可以添加任意修饰符
作用域在外部类
外部类访问成员内部类的成员:先创建内部类再调用,私有成员也可调用
成员内部类与外部类成员重名时,调用遵循就近原则,可用
外部名.this.成员名
形式调用外部成员
外部其他类可以访问成员内部类:
public class A {
public static void main(String[] args) {
A a = new A(); //先创建A类
B b = A.new B(); //再创建B类
}
}
class A {
class B{}
}
静态内部类
定义在外部类的除方法代码块的地方,有static修饰
可以访问外部所有静态成员,包括私有的,不能访问非静态成员
可以添加任意修饰符
枚举类
enum Color //自动继承Enum类
{
RED, GREEN, BLUE;
}
//使用
...
Color c1 = Color.RED;
Soprint(c1); //输出RED
...
枚举本质:定义类,并在内部创建静态final类
class Color
{
public static final Color RED = new Color();
public static final Color BLUE = new Color();
public static final Color GREEN = new Color();
}
for和switch中使用:
for (Color myVar : Color.values()) {
System.out.println(myVar);
}
Color myVar = Color.BLUE;
switch(myVar) {
case RED:
System.out.println("红色");
枚举类内置方法:
values()
: 返回枚举类中所有的值。ordinal()
:方法可以找到每个枚举常量的序号,就像数组索引一样。valueOf()
:方法返回指定字符串值的枚举常量。
自定义类的枚举
步骤:
将构造器私有,防止直接
new
去掉
setXxxx
方法,防止属性被修改在类的内部直接创建静态固定对象
可以添加
final
class Season {
private String name;
public static final Season SPPING = new Season("春天"); //全大写
public static final Season WINTER = new Season("冬天");
public static final Season AUTUMM = new Season("秋天");
public static final Season SUMMER = new Season("夏天");
private Season(String name) {} //构造器
}
//方法2
//public static final Season SUMMER = new Season("夏天");用SPPING("春天");代替
enum Season {
SPPING("春天");
WINTER("冬天"), AUTUMM("秋天"), SUMMER("夏天");
private String name;
private Season(String name) {} //构造器
}
//1.使用的是enum不是class
//2.如果有多个,可以用,间隔
//3.要将SPPING("春天")写在最前面
可以提供
get方法
,但不要提供set方法
注解
Override
注解:写在方法前,表示重写
Deprecated
注解:用于表示某个类,方法已过时。可以修饰方法,类,字段,包,参数等
SuppressWarning
注解:用于抑制运行时的警告信息
异常处理
作用:当出现程序错误时执行另一段代码,而不是直接程序崩溃运行不了,可以让程序具有更好的容错性,是程序更加健壮
异常类型:主要是编译类型、运行类型
常用异常分类图:
Throwable
类:是所有异常和错误的超类Error
:定义了在通常环境下不希望被程序捕获的异常。一般指的是 JVM 错误StackOverflowError
:栈溢出OutOfMemoryError
:内存耗尽
Exception
:类用于用户程序可能出现的异常情况,它也是用来创建自定义异常类型类的RuntimeException
:运行时异常NullPointerException
:访问了一个NULL对象成员,空指针异常ArithmeticException
:算术错误异常,如0作除数ArrayIndexOutOfBoundsException
:数组索引越界ClassCastException
:类型转换异常NumberFormatException
:数字转化格式异常,比如字符串到 float 型数字的转换无效
FileNotFoundException
:未找到文件ClassNotFoundException
:没有找到类
try-catch(finally可不写)
try {
//代码1
//代码2
} catch(异常类型 e) {
//代码3
} finally { //不管是否异常,都执行代码4
//代码4
}
//try后接多个catch
try {
} catch(异常类型1 e) {
} catch(异常类型2 e) {
}
//没catch
try {
} finally { //若出现异常则throw给上级处理
}
如果代码1发生异常,后面的代码2不会执行,跳到
catch
catch
必须指明异常类型try
后面可接多个catch
可以只有
try
+finally
没catch
,相当于throws
若
catch
有return
,finally
也有return
,最终返回的是finally
的
throws与throw
throws
:
public void func() throws 异常类型 {} //主要用在方法中,异常类型可以是异常的父类
public void func() throws 异常类型1,异常类型2 {} //可以多个类型
对于运行类型异常,默认
throws
方法处理子类重写父类方法时,其抛出类型必须与父类方法的一致,或者是父类方法的异常类型的子类
方法1调用方法2时,若编译类型异常,方法1也必须
throws
异常类型,运行类型则不用
throw:
throw new 异常类型("xxxx"); //向上级,或try抛出异常
throws与throw的区别:
throw与try同时使用
try {
throw new 异常类型1("xxxx");
} catch (异常类型1 e) {
} catch (异常类型2 e) { //try里面还可能出现其他类型
}
自定义异常
if(xxx) { //如果满足xxx条件就抛出异常
throw new 异常类型1("xxxx");
}
八大包装类
包装类与基本数据类的转换:
int m = 100;
Integer im = m; //自动装箱,即int类的值直接赋给Integer
int n = im; //自动拆箱,相反
//例题
Object obj = true?new Integer(1) : new Double(2);
System.out.println(obj); //输出1.0,三元运算符是整体,Double会提高精度
包装类型与String类的转换:
//包装类->String
Integer i = 10;
String s1 = i.toString(); //方法1
String s2 = String.valueOf(i); //方法2
String s3 = i + ""; //方法3
//String->包装类
Integer j = new Integer(s1); //方法1
Integer k = Integer.valueOf(s2);//方法2
Integer等包装类有大量内置方法
String类
##String
创建:
String s1 = "inin"; //方法1
String s2 = new String("inin"); //方法2,与方法1有不同
//s1[0]错误,需用方法获取
方法1是直接在常量池中操作数据;而方法2是在堆中创建空间操作常量池的数据
注意: == 是判断两边是否都在堆同一地址或都在常量池同一地址
String c = "in" + "in"
常量相加,看的是池String c = a + b
变量相加,是在堆中,则是在堆中创建空间指向a
,b
中的数据,类似于方法2对象中的
String
是属于在堆中,如person.name
比较的是堆,不是常量池
常用方法:
StringBuffer
与String的区别:
String创建后一旦修改值,则在常量池中新开辟地址存放新的值,然后重新指向新的值,本质是更改地址;StringBuffer值存放在堆中,不用更改地址
StringBuffer s1 = new StringBuffer(); //默认长度为16
StringBuffer s2 = new StringBuffer(100); //指定长度
StringBuffer s3 = new StringBuffer("inin"); //长度为 输入的字符串 + 16
String 与StringBuffer转换:
//String 转 StringBuffer
String str = "inin";
StringBuffer nstr = new StringBuffer(str); //str本身没影响
//StringBuffer 转 String
StringBuffer s = new StringBuffer("inin");
String b1 = s.toString(); //方法1
String b2 = new String(s); //方法2
StringBuilder
特点:类似StringBuffer
,非线程安全,比StringBuffer快,但建议用在字符串缓冲区被单个线程使用的时候
比较
Arrays类
内含许多数组操作的方法,可直接通过Arrays.xxx(xxx)
方法调用
常用方法:
int binarySearch(type[] a, type key)
:在已升序排序好的数组a中查询key,返回其位序,若空则返回负数type[] copyOf(type[] original, int length)
:复制数组boolean equals(type[] a, type[] a2)
:两数组是否相等void fill(type[] a, type val)
:val赋值给a所有元素void sort(type[] a)
:升序排序,底层原理:双轴快排String toString(type[] a)
:将数组转换为字符串,通常用于输出
其他类
System类、BigInteger类:处理较大的整数、BigDecimal:处理精度较高的小数
集合
Vector
解析:动态数组
与ArrayList区别:
Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的
ArrayList 在性能方面要优于 Vector,因为没有Synchronized加锁
ArrayList扩容增加50%,Vector默认100%(可自定义扩多少倍)
Vector类的所有方法都是同步的,可以由两个线程安全地访问一个Vector对象
ArrayList
解析:没有固定大小的数组,查询效率高,增删效率低
import java.util.ArrayList; // 引入 ArrayList 类
ArrayList<E> objectName =new ArrayList<>(); // 初始化,E是数据类型
注意:E只能为引用类型,即八大包装类
常用方法:
objectName.add(X); //添加x到数组中
objectName.get(1); //取值objectName[1]
objectName.set(1, X); //插入X到objectName[1]
objectName.remove(3); //删除objectName[3]
objectName.size(); //数组长度
Collections.sort(objectName);//排序
LinkedList
底层实现:链表,增删效率高,查询效率低
import java.util.LinkedList; // 引入 LinkedList 类
LinkedList<E> list = new LinkedList<E>(); // 普通创建方法
LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表
特有方法:
TreeSet
底层实现:红黑树
特点:有序,不可重复
HashSet
底层实现: HashMap
特点:无序,不可重复,不是线程安全
Hashtable
HashMap
TreeMap
底层实现:红黑树,二叉树
特点:有序,键不可重复,值可以重复
泛型
常用于接口或类
class Person<E> { //泛型类一般用于类中的属性类型不确定的情况下
E data;
public Person(E data) {
this.data = data;
}
}
T、E只能是引用类型(包装类),
泛型指定具体类型后,可传入该类型的子类类型,例:
Person<Father> a = new Person<Father>(new Son())
简写:
Person<Father> a = new Person<>()
自定义泛型类:
class Person<T, R...> { //可以有多个泛型
T sum;
}
//创建实例
Person<T, R..> tom = new Person<>(T);
使用泛型数组,不能初始化,因为不知道其数据类型,不知道开辟多大空间
静态方法不能使用类的泛型
创建实例时,自动转换
创建对象时指定泛型的类型,没有指定则默认为Object
自定义泛型方法:
public<A> void func(A a) { //接在在修饰符后面
}
//与方法使用泛型区别
public E func(E e) {}
//传参时,自动转换成包装类
func(100); //转换成Integer
泛型继承和通配符:
泛型不具备继承性:
Person<Object> person = new Person<String>();
错误<?>:表示可以传入任意泛型
<? extends A>:支持A类以及A类的子类,规定了泛型的上限
<? super A>:支持A类以及A类的父类,规定了泛型的下限
反射
java程序运行总共有三个阶段:
代码阶段/编译阶段:javac将代码编译成字节码文件
Class类加载阶段:类加载器将字节码文件的类加载到堆中的Class类中
运行阶段:创建对象实例时,该对象知道他是属于哪个Class对象
反射:
根据字符串名获得其对应的类对象实例
Class Dog { }
Class c1 = Class.forName("Dog");
//方法2:对象.getClass()
//方法3:任何类型.class
根据字符串名获得对应的方法对象实例
Class Dog { func() }
Class c1 = Class.forName("Dog");
Method method1 = c1.getMethod("func");
通过方法对象调用方法
method1.invoke(oname);
//方法.invoke(对象)
//表示调用oname对象里的method1方法
//与传统的对象名.方法名不同
Dog dog1 = new Dog("jj", 12);
Dog dog2 = new Dog("kk", 24);
Class d1 = Class.forName("Dog"); //获取类实例d1,包含Dog类的属性和方法
Method m1 = d1.getMethod("getName"); //获取Dog类中名为getName的方法实例m1
System.out.println("===" + m1.invoke(dog1) + "====="); //调用方法实例m1,用于dog1实例
System.out.println("===" + m1.invoke(dog2) + "====="); //调用方法实例m1,用于dog2实例
输出:
多线程
运行java程序,会创建一个进程
进程会创建一个main线程,运行main主方法
如果有创建线程,则main会创建线程T0
进程什么时候结束:所有线程都运行完
若main主线程运行完,T0线程还运行,则进程不结束
若T0主线程运行完,main线程还运行,则进程不结束
主线程可创建多个子线程
子线程也可创建多个线程
实现Runnable接口来创建线程:
创建类T3继承
Runnable
接口,并重写run
方法main
中创建T3实例t3再创建线程
Thread
类的实例thread1
和2,调用Thread
类的start
方法创建线程
线程常用方法:
join 方法:主线程使用join方法表示:主线程进入阻塞状态,直到子线程运行结束后,主线程继续运行
将子线程设置为守护线程:thread1.setDaemon(true)
特点:主线程结束后,无论子线程(守护线程)是否永久执行,都会跟着结束
线程状态:
初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。 线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
阻塞(BLOCKED):表示线程阻塞于锁。
等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
终止(TERMINATED):表示该线程已经执行完毕。
多线程访问(运行)同一对象:
Dog dog = new Dog();
Thread thread1 = new Thread(dog);
Thread thread2 = new Thread(dog);
Thread thread3 = new Thread(dog);
表示创建三个线程,其都运行dog对象,从而引出同步互斥概念
类似线程都指向在内存中的对象,以指针指向的方式,非各复制一个对象
java8新特性
Lambda与方法引用与函数式接口为同一类知识,
Lambda与方法引用多用于函数式接口
Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
简化编写代码
语法
(参数) ->(函数或语句)
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。指向一个方法
//例子
Comparator<String> com1 = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
Comparator<String> com1 = String :: compareTo;
//表示,创建一个Comparator函数式接口的对象com1,用String类里的compareTo方法来重写
System.out.println(com1.compare("abc", "abb"));
//例子
//计算器函数式接口
@FunctionalInterface
public interface Calculator {
//抽象方法作用:求绝对值
int getAbs(int num);
}
public class Abs {
public static void main(String[] args) {
// 使用Lambda表达式
method((int num) -> {
int result;
if (num>=0) {
result = num;
}else {
result = -num;
}
return result;
});
// 方法引用的意义:Math类当中有一个abs静态方法,已经有了现成的功能,直接拿过来用
method(Math::abs);//将Math里的abs方法传入method方法
}
public static void method(Calculator cal) {//函数作参数
int result = cal.getAbs(-25);
System.out.println("结果是"+result);
}
}
函数式接口:指接口只声明一个抽象方法
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
}
默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。
新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
应用场景:java层面处理redis等NoSQL型数据库
让你以一种声明的方式处理数据
是一个类
终端操作(例如 Stream.forEach
或 IntStream.sum
)可能会遍历流以产生结果或副作用。执行终端操作后,stream pipeline被认为消耗掉了,不能再使用;如果需要再次遍历同一个数据源,则必须返回数据源获取新的流
Date Time API − 加强对日期与时间的处理。
Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。