类的继承
在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类或基类,子类会自动拥有父类所有可继承的属性和方法。
关键字:extends
子类在继承父类的时候,会自动拥有父类所有公共的成员
注意:
1、在Java中,类只支持单继承,不允许多重继承,也就是说一个类只能有一个直接父类。
2、多个类可以继承同一个父类。
3、在Java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类。
重写父类方法
在Java中,子类会自动继承父类中公共的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。
注意:子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限。如父类中的方法访问权限是public,子类重写父类该方法的访问权限就不能是private。
关键字:super
1、使用super关键字调用父类的成员变量和成员方法。
2、使用super关键字调用父类的构造方法。
通过super调用父类构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次,否则程序在编译期间就会报错。
在子类的构造方法中一定会调用父类的某个构造方法,这时可以在子类的构造方法中通过super关键字指定调用父类的哪个构造方法,如果没有指定,在实例化子类对象时,会默认调用父类无参的构造方法。
(1)super能出现在实例方法和构造方法中。
(2)super的语法是“super.”和“super()”。
(3) super不能出现在静态方法中。
(4) super大部分情况下是可以省略的。
(5)super.什么时候不能省略呢?
别急,我们想一下this指向的是什么,是当前对象自己。super和this类似,它指向了当前对象自己的父类型特征(也就是继承过来的那些东西)。
super和this区别是:this可以看做一个引用变量,保存了该对象的地址,是当前对象整体,而super代表的是父类型特征,是子类局部的一些东西,这些继承过来的东西已经在子类里面了,你可以输出整体this,但不能输出父类型特征super。因为super指向的东西不是一个整体,没法打印输出。
System.out.println(this); //输出this.toString()的值
System.out.println(super); //编译报错,需要'.'
当在子类对象中,子类想访问父类的东西,可以使用“super.”的方式访问。例如:方法覆盖后,子类内部虽然重写了父类的方法,但子类也想使用一下父类的被覆盖的方法,此时可以使用“super.”的方式。当子类中出现和父类一样的属性或者方法,此时,你要想去调用父类的那个属性或者方法,此时“super.”不能省略。
this和super都只能在对象内部使用。
this代表当前对象本身,super代表当前对象的父类型特征。
“this.”是一个实例对象内部为了区分实例变量和局部变量。
而“super.”是一个实例对象为了区分是子类的成员还是父类的成员。
父类有,子类也有,子类想访问父类的,“super.”不能省略。
(6)super()只能出现在构造方法的第一行,通过当前的构造方法去调用“父类”中的对应的构造方法,目的是:创建子类对象时,先初始化父类型特征。
用通俗的话来讲,要想有儿子,得先有父亲。
我们来看下面代码:
写两个类,Animal和Cat,Cat继承Animal。
//父类,Animal类 class Animal { //构造函数 public Animal() { System.out.println("Animal类的无参数构造函数执行"); } } //子类,Cat类 class Cat extends Animal{ //构造函数 public Cat() { System.out.println("Cat类的无参数构造函数执行"); } }
执行下面一行代码:
public static void main(String[] args) {
Cat cat = new Cat();
}
运行输出结果为:
Animal类的无参数构造函数执行
Cat类的无参数构造函数执行
我们发现实例化一个子类的对象,也就是调用了子类的构造方法,为什么父类的无参数构造方法也执行了,并在子类构造方法执行之前就已经执行了父类的无参数构造方法,好奇怪。
刚刚在上面的super关键字的使用第6点,我已经说了,super()和this()方法一样,都只能在构造方法的第一行出现。我们猜想,难道子类的构造方法第一行有一个隐形的super()方法?答案是肯定的。
我们把子类的构造方法的第一行给它加上super():
//子类,Cat类
class Cat extends Animal{
//构造函数
public Cat() {
super();
System.out.println("Cat类的无参数构造函数执行");
}
}
再执行下面代码:
Cat cat = new Cat();
运行输出结果为:
Animal类的无参数构造函数执行
Cat类的无参数构造函数执行
Object类 欧布斯
Object是所有类的父类,即每个类都直接或间接继承自该类,因此Object类通常被称为超类,基类或根类。当定义一个类时,如果没有使用extends关键字为这个类显式地指定父类,那么该类会默认继承Object类。
Object类常用方法(12个)
final 关键字
final关键字可用于修饰类、变量和方法,它有“不可更改”或者“最终”的含义,因此被final修饰的类、变量和方法将具有以下特性:
1、final修饰的类不能被继承。
2、final修饰的方法不能被子类重写。
3、final修饰的变量(成员变量和局部变量)是常量,只能赋值一次。
案例:
//final 修饰的类不能被继承
final class Animal {
}
class Dog extends Animal { //Dog类想继承被final修饰过的类Animal会报错。
}
// final 关键字修饰方法不能被重写,编译会报错
//定义Animal类
class Animal {
//使用final关键字修饰shout()方法
public final void shout(){
}
}
//定义Dog类继承Animal类
class Dog extends Animal {
//重写Animal类的shout()方法
public void shout(){
}
}
// final 关键字修饰成员变量和局部变量被称为常量,只能被赋值一次
public class Example10 {
public static void main(String[] args) {
final int num=2; //局部变量num第一次赋值等于2,使用final关键字
num=4; //局部变量num第二次赋值等于4,编译报错
}
}
// final 关键字修饰成员变量和局部变量被称为常量,只能被赋值一次
public class Example10 {
//final 修饰的成员变量,必须在声明的同时进行赋值,否则编译器报错
final int m;
public static void main(String[] args) {
//final修饰的局部变量,可以先声明,再进行一次赋值
final int n;
n=4;
}
}
抽象类和接口
抽象类:当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式是无法确定的,例如,前面在定义Animal类时,shout()方法用于表示动物的叫声,但是不同的动物,叫声也是不同的,因此在shout()方法中无法准确描述动物的叫声,如何能使Animal类中既包含shout()方法,又无须提供其方法的实现呢?
针对上述这种情况,Java提供了抽象方法来满足这种需求。抽象方法必须使用abstract关键字来修饰,并且在定义方法时不需要实现方法体。当一个类中包含了抽象方法,那么该类也必须使用abstract关键字来修饰,这种使用abstract关键字修饰的类就是抽象类。
抽象类及抽象方法定义的基本语法格式如下:
//定义抽象类
[修饰符] abstract class 类名 {
//定义抽象方法
[修饰符] abstract 方法返回值类型 方法名(参数列表);
//其他方法或属性
}
注意:包含抽象方法的类必须定义为抽象类,但抽象类中可以不包含任何抽象方法。
小提示:定义抽象方法只需要在普通方法上增加abstract关键字,并把普通方法的方法体(大括号以及大括号中的部分)全部去掉,然后再方法名称后增加英文分号即可,例如:public abstract void shout();
//定义抽象类 Animal
abstract class Animal {
//定义抽象方法shout()
public abstract void shout();
}
//定义Dog类继承抽象类Animal
class Dog extends Animal {
//实现抽象方法shout(),编写方法体
public void shout(){
System.out.println("汪汪......");
}
}
//定义测试类
public class Example12 {
public static void main(String[] args){
Dog dog=new Dog(); //创建Dog类的实例对象
dog.shout(); //调用dog对象的shout()方法
}
}
控制台打印结果:
汪汪......
读者笔记:普通方法的特点是有一对大括号{ },即方法体,有方法体的方法一定可以被对象直接使用,而抽象方法是指没有一对大括号{ }方法体的方法。
接口:如果抽象类中的所有方法都是抽象的,则可以将这个类定义为Java中的另一种形式----接口。接口是一种特殊的抽象类,它不能包含普通方法,其内部的所有方法都是抽象方法,它将抽象进行得更为彻底。
在JDK8中,对接口进行了重新定义,接口中除了抽象方法外,还可以有默认方法和静态方法(也叫类方法),默认方法使用default修饰,静态方法使用static修饰,并且这两种方法都允许有方法体。
接口定义的基本语法格式如下:
[修饰符] interface 接口名 [extends 父接口1,父接口2, ....... 父接口n] {
[public] [static] [final] 常量类型 常量名=常量值;
[public] [abstract] 方法返回值类型 方法名([参数列表])
[public] default 方法返回值类型 方法名 ([参数列表]){
//默认方法的方法体
}
[public] static 方法返回值类型 方法名([参数列表]) {
//类方法(静态方法)的方法体
}
}
注:extends 父接口1,父接口2,.... 表示定义一个接口时,可以同时继承多个父接口,这也是为了解决类的单继承的限制。在接口内部可以定义多个常量和抽象方法,定义常量时必须进行初始化赋值,定义默认方法和静态方法时,可以有方法体。
接口中可以包含三类方法:抽象方法、默认方法和静态方法,其中静态方法可以通过 《接口名.方法名》 的形式来调用,而抽象方法和默认方法只能通过接口实现类的实例对象来调用。因此需要定义一个接口的实现类,该类通过implements关键字实现当前接口,并实现接口中的所有抽象方法。
定义接口的实现类语法格式如下:
[修饰符] class 类名 [extends 父类名] [implements 接口1,接口2,....,接口n] {
.
.
.
}
注意:接口不能实例化对象;接口实现类,必须实现接口中所有抽象方法
//定义了Animal接口
interface Animal {
int ID=1;
void breathe();
//定义一个默认方法
default void getType (String type){
System.out.println("该动物属于:"+type);
}
//定义一个静态方法
static int getID(){
return Animal.ID;
}
}
//Dog类实现了Animal接口
class Dog implements Animal {
//实现breathe()方法
public void breathe(){
System.out.println("狗在呼吸");
}
}
//定义测试类
public class Example13{
public static void main(String[] args){
System.out.println(Animal.getID); //通过接口名调用类方法
Dog dog=new Dog(); //创建Dog类的实例对象
System.out.println(dog.ID); //在实现类中获取接口全局变量
dog.breathe(); //调用dog对象的breathe()方法
dog.getType("犬科"); //通过接口实现类Dog的实例化对象,调用接口默认方法
}
}
控制台打印结果:
1
1
狗在呼吸
该动物属于:犬科
通过接口实现类Dog的实例化对象可以访问接口中的常量、接口实现方法以及默认方法,而接口中的静态方法则可以直接使用接口名调用。需要注意的是,接口的实现类,必须实现接口中的所有抽象方法,否则程序编译报错。
接口继承接口案例:
//定义了Animal接口
interface Animal {
int ID=1; //定义全局变量
void breathe(); //定义抽象方法breathe()
//定义一个默认方法
default void getType (String type){
System.out.println("该动物属于:"+type);
}
//定义一个静态方法
static int getID(){
return Animal.ID;
}
}
//定义了LandAnimal接口,并继承了Animal接口
interface LandAnimal {
void run(); //定义抽象方法run()
}
//Dog类实现了LandAnimal接口
class Dog implements LandAnimal{
//实现breathe()方法
public void breathe(){
System.out.println("狗在呼吸");
}
//实现run()方法
public void run(){
System.out.println("狗在陆地上跑");
}
}
//定义测试类
public class Example13{
public static void main(String[] args){
System.out.println(Animal.getID); //通过接口名调用类方法
Dog dog=new Dog(); //创建Dog类的实例对象
System.out.println(dog.ID); //在实现类中获取接口全局变量
dog.breathe(); //调用dog对象的breathe()方法
dog.getType("犬科"); //通过接口实现类Dog的实例化对象,调用接口默认方法
dog.run(); //调用dog对象的run()方法
}
}
控制台打印结果:
1
1
狗在呼吸
该动物属于:犬科
狗在陆地上跑
Java接口的特征进行归纳,具体如下:
1、在JDK8之前,接口中的方法都必须是抽象的,并且方法不能包含方法体。在调用抽象方法时,必须通过接口的实现类的对象才能调用实现方法。从JDK8开始,接口中的方法除了包含抽象方法外,还包含默认方法和静态方法,默认方法和静态方法都可以有方法体,并且静态方法可以直接通过《接口.方法名》来调用。
2、当一个类实现接口时,如果这个类是抽象类,只需实现接口中的部分抽象方法即可,否则需要实现接口中的所有抽象方法。
3、一个类可以通过implements关键字同时实现多个接口,被实现的多个接口之间要用英文逗号(,)隔开。
4、接口之间可以通过extends关键字实现继承,并且一个接口可以同时继承多个接口,接口之间用英文逗号隔开。
5、一个类在继承一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字之前。具体示例如下:
class A extends B implements C { //先继承,再实现
.
.
.
}
多态
在Java中,多态是指不同类的对象在调用同一个方法时所呈现的多种不同行为。通常来说,在一个类中定义的属性和方法被其他类继承或重写后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现的多种不同形态。通过多态,消除了类之间的耦合关系,大大提高了程序的可扩展性和可维护性。
Java的多态性是由类的继承、方法重写以及父类引用指向子类对象体现的。
//定义抽象类Animal
abstract class Animal {
abstract void shout(); //定义抽象方法shout()
}
//定义Cat类继承Animal抽象类
class Cat extends Animal {
//实现shout()方法
public void shout(){
System.out.println("喵喵......");
}
}
//定义Dog类继承Animal抽象类
class Dog extends Animal{
//实现shout()方法
public void shout(){
System.out.println("汪汪......");
}
}
//定义测试类
public class Example15{
public static void main(String[] args){
Animal cat=new Cat(); //将Cat类对象当做Animal类型来使用
Animal dog=new Dog(); //将Dog类对象当做Animal类型来使用
cat.shout(); //调用cat对象的shout()方法
dog.shout(); //调用dog对象的shout()方法
}
}
控制台打印结果:
喵喵......
汪汪......
对象的类型转换
向上转型:将子类对象当做父类类型使用
Animal cat=new Cat(); //将Cat类对象当做Animal类型来使用
Animal dog=new Dog(); //将Dog类对象当做Animal类型来使用
注:将子类对象当做父类使用时不需要任何显式声明,需要注意的是,此时不能通过父类变量去调用子类特有的方法。
向下转型:对象向下类型转换时,必须转换为本质类型,否则转换时会出现错误。
Animal an1=new Dog(); //将Dog类对象当做Animal类型来使用
Cat cat=(Cat) an1; //将Dog类型强制转换成Cat类型,会报错
提示Dog类型不能转换成Cat类型,为了避免这种异常情况的发生,Java提供了一个关键字instanceof,它可以判断一个对象是否为某个类(或接口)的实例或者子类实例。
对象(或者对象引用变量)instanceof 类(接口)
//定义测试类
public class Example17 {
public static void main(String[] args){
Animal anl = new Animal();
if(an1 instanceof Cat){ //判断an1本质类型
Cat cat=(Cat) an1;
cat.shout();
cat.catchMouse();
}else{
System.out.println("该类型的对象不是Cat类型!");
}
}
}
控制台输出结果:
该类型的对象不是Cat类型!
内部类
在Java中,允许在一个类的内部定义类,这样的类称作内部类,内部类可以分为4种形式:成员内部类、局部内部类、静态内部类、匿名内部类。
成员内部类
在成员内部类中,可以访问外部类的所有成员
//定义外部类Outer
class Outer {
int m=0; //定义外部类成员变量
//定义外部类成员方法
void test1(){
System.out.println("外部类成员方法");
}
}
//定义成员内部类Inner
class Inner {
int n=1;
//1.定义内部类方法,访问外部类成员变量和方法
void show1(){
System.out.println("外部类成员变量m="+m);
test1();
}
void show2(){
System.out.println("内部类成员方法");
}
}
//定义外部类方法,访问内部类变量和方法
void test2(){
Inner inner=new Inner();
System.out.println("内部类成员变量n"+inner.n);
inner.show2();
}
//定义测试类
public class Example18 {
public static void main(String[] args){
Outer outer=new Outer(); //创建外部类对象
Outer.Inner inner = new Outer().new Inner(); //创建内部类对象
inner.show1(); //测试在成员内部类中访问外部内成员变量和方法
inner.show2(); //测试在外部内中访问内部类成员变量和方法
}
}
控制台打印结果
外部类成员变量m=0
外部类成员方法
内部类成员变量n=1
内部类成员方法
成员内部类可以访问外部类所有成员,同时外部类也可以访问成员内部类的所有成员。
通过外部类对象创建的内部类对象,这样就可以操作内部类中的成员。
创建内部类对象的具体语法格式如下:
外部类名.内部类名 变量名=new 外部类名().new 内部类名();
局部内部类
局部内部类也叫方法内部类,就是定义在某个局部范围中的类,它和局部变量一样,都是在方法中定义的,其有效范围只限于方法内部。
在局部类中,局部内部类可以访问外部类的所有成员变量和方法,而局部内部类中的变量和方法却只能在创建该局部内部类的方法中进行访问。
//定义外部类Outer
class Outer {
int m=0; //定义外部类成员变量
//定义外部类成员方法
void test1(){
System.out.println("外部类成员方法");
}
//定义外部类方法,访问内部类变量和方法
void test2(){
//1.定义局部内部类Inner,在局部内部类中访问外部类变量和方法
class Inner {
int n=1;
//1.定义内部类方法,访问外部类成员变量和方法
void show(){
System.out.println("外部类变量m="+m);
test1();
}
}
//2.在创建局部内部类对象inner,调用局部内部类变量和方法
Inner inner=new Inner();
System.out.println("局部内部类成员变量n"+inner.n);
inner.show();
}
}
//定义测试类
public class Example18 {
public static void main(String[] args){
Outer outer=new Outer(); //创建外部类对象
inner.show(); //测试外部类对象调用创建了局部内部类的方法
}
}
控制台打印结果
内部类成员变量n=1
外部类变量m=0
外部类成员方法
静态内部类
所谓静态内部类,就是使用static关键字修饰的成员内部类。
静态类内部类中只能访问外部类的静态成员,同时通过外部类访问静态内部类成员时,可以跳过外部类从而直接通过内部类访问静态内部类成员。
创建静态内部类对象的基本语法格式如下:
外部类名.静态内部类名 变量名 = new 外部类名.静态内部类名();
//定义外部类Outer
class Outer {
static int m=0; //定义外部类静态成员变量m
static class Inner {
void show(){
//静态内部类访问外部类静态成员
System.out.println("外部类静态变量m"+m);
}
}
}
//定义测试类
public class Example20 {
public static void main(String[] args){
//静态内部类可以直接通过外部类创建
Outer.Inner inner =new Outer.Inner();
inner.show(); //测试静态内部类对象调用创建了静态内部类的方法
}
}
控制台打印结果
外部类静态变量m=0
匿名内部类
在Java中调用某个方法时,如果该方法的参数是一个接口类型,除了可以传入一个参数接口实现类,还可以使用匿名内部类实现接口来作为该方法的参数。匿名内部类其实就是没有名称的内部类,在调用包含有接口类型参数的方法时,通常为了简化代码,不会创建一个接口的实现类作为方法参数传入,而是直接通过匿名内部类的形式传入一个接口类型参数,在匿名内部类中直接完成方法的实现。
创建匿名内部类的基本语法格式如下:
new 父接口(){
//匿名内部类实现部分
}
//定义动物类接口
interface Animal {
void shout();
}
//定义测试类
public class Example21 {
public static void main(String[] args){
String name="小花";
//定义匿名内部类作为参数传递给animalShout()方法
animalShout(new Animal() {
//实现shout()方法
public void shout(){
//JDK 8 开始,局部内部类、匿名内部类可以访问非final的局部变量
Systen.out.println(name+"喵喵...");
}
});
}
//定义静态方法 animalShout(),接收接口类型参数
public static void animalShout(Animal an) {
an.shout(); //调用传入对象an的shout()方法
}
}
控制台打印结果
小花喵喵...
JDK 8 的Lambda表达试
Lambda表达式,这种表达式只针对有一个抽象方法的接口实现,以简洁的表达式实现接口功能来作为方法参数。
一个Lamdba表达式由三个部分组成,分别为参数列表、"->"和表达式主体,其语法格式如下:
([数据类型 参数名,数据类型 参数名,...]) -> {表达式主体}
Lamdba表达式,本质就是接口中抽象方法的具体实现,如果表达式主体只有一条语句,那么可以省略包含主体的大括号。
//定义动物类接口
interface Animal {
void shout(); //定义方法shout()
}
//定义测试类
public class Example22 {
public static void main(String[] args){
String name="小花";
//1.定义匿名内部类作为参数传递给animalShout()方法
animalShout(new Animal() {
//实现shout()方法
public void shout(){
//JDK 8 开始,局部内部类、匿名内部类可以访问非final的局部变量
Systen.out.println("匿名内部类输出:"+name+"喵喵...");
}
});
//2.使用Lambda表达式作为参数传递给animalShout()方法
animalShout(()->Sytem.out.println("Lambda表达式输出:"+name+"喵喵..."));
}
//创建一个animalShout()静态方法,接收接口类型的参数
public static void animalShout(Animal an) {
an.shout(); //调用传入对象an的shout()方法
}
}
控制台打印结果
匿名内部类输出:小花喵喵...
Lambda表达式输出:小花喵喵...
函数式接口
虽然Lambda表达式可以实现匿名内部类的功能,但在使用时却有一个局限,即接口中有且只有一个抽象方法时才能使用Lambda表达式代替匿名内部类。
所谓函数式接口是指有且仅有一个抽象方法的接口。
在JDK 8 中,专门为函数式接口引入了一个@FunctionalInterface注解,该注解只是显式地标注了接口是一个函数式接口,并强制编译器进行严格的检查,确保该接口是函数式接口,如果不是函数式接口,那么编译器就会报错,而对程序运行并没有实质上的影响。
//定义无参、无返回值的函数式接口
@FunctionalInterface
interface Animal {
void shout();
}
//定义有参、有返回值的函数式接口
interface Calculate {
int sum(int a,int b)
}
public class Example23{
public static void main(String[] args){
//分别两个函数式接口进行测试
animalShout(() -> Systen.out.println("无参、无返回值的函数式接口调用"));
showSum(10,20,(x,y) -> x+y);
}
//创建一个动物叫的方法,并传入接口对象Animal作为参数
private static void animalShout(Animal animal){
animal.shout();
}
//创建一个求和的方法,并传入两个int类型以及接口Calculate类型的参数
private static void showSum(int x,int y,Calculate calculate){
System.out.println(x+"+"+y+"的和为:"calculate.sum(x,y));
}
}
控制台输出结果:
无参、无返回值的函数式接口调用
10+20的和为:30
方法引用与构造器引用
种类 | Lambda表达式 | 对应的引用示例 |
类名引用普通方法 | (x,y,....) -> 对象名x.类普通方法名(y,......) | 类名::类普通方法名 |
类名引用静态方法 | (x,y,....) -> 类名x.类静态方法名(x,y,......) | 类名::类静态方法名 |
对象名引用方法 | (x,y,....) -> 对象名.实例方法名(x,y,......) | 对象名::实例方法名 |
构造器引用 | (x,y,....) -> new类名(x,y,......) | 类名::new |
类名引用普通方法 案例
//定义一个函数式接口
@FunctionalInterface
interface Printable{
void print(StringUtils su,String str){
}
}
class StringUtils{
public void pringUpperCase(String str){
System.out.println(str.toUpperCase());
}
}
//定义测试类
public class Example27{
private static void printUpper(StrintUtils su,String text,Printable pt){
pt.print(su,text);
}
public static void main(String[] args){
//使用Lambda表达式方式
printUpper(new StringUtils(),"hello",
(object,t) -> object,printUpperCase(t));
//使用方法引用的方式
printUpper(new StringUtils(),"hello",
StringUtils::printUpperCase);
}
}
控制台输出结果:
HELLO
HELLO
类名引用静态方法 案例
//定义一个函数式接口
@FunctionalInterface
interface Calcable{
int calc(int num);
}
//定义一个类,并在类中定义一个静态方法
class Math{
//定义一个求绝对值方法
public static int abs (int num){
if (num<0){
return - num;
}else{
return num;
}
}
}
//定义测试类
public class Example24{
private static void printAbs(int num, Calcable calcable){
System.out.println(calcable.calc(num));
}
public static void main(String[] args){
//使用Lambda表达式方式
printAbs(-10, n -> Math.abs(n));
//使用方法引用的方式
printAbs(-10, Math::abs(n));
}
}
控制台输出结果:
10
10
对象名引用方法
//定义一个函数式接口
@FunctionalInterface
interface Printable {
void print(String str);
}
class StringUtils {
public void printUpperCase(String str){
System.out.println(str.toUpperCase());
}
}
//定义测试类
public class Example25 {
private static void printUpper(String text,Printable pt){
pt.print(text);
}
public static void main(String[] args){
StringUtils stu=new StringUtils();
//使用Lambda表达式
printUpper("hello",t -> stu.printUpperCase(t));
//使用方法引用的方式
printUpper("hello",stu::printUpperCase);
}
}
控制台输出:
HELLO
HELLO
构造器引用方法
//定义一个函数式接口
@FunctionalInterface
interface PersonBuilder {
Person buildPerson(String name);
}
//定义一个Person类,并添加有参构造方法
class Person {
private String name;
public Person(String name){
this.name=name;
}
public String getName(){
returun name;
}
}
//定义测试类
public class Example26 {
public static void printName(String name,PersonBuilder builder){
System.out.println(builder.buildPerson(name).getName());
}
public static void main(String[] args){
//使用Lambda表达式
printName("赵丽颖", name -> new Person(name));
//使用构造器引用的方式
printName("赵丽颖",Person::new);
}
}
异常
在Java中什么算是异常?
Java语言中引入了异常(Exception),以异常类的形式对这些非正常情况进行封装,并通过异常处理机制对程序运行时发生的各种问题进行处理。
异常案例:
public class Example28 {
//下面的方法实现了两个整数相除
public static int divide(int x,int y){
int result = x / y; //定义一个变量result记录两个数相除的结果
return result; //将结果返回
}
public static void main(String[] args){
int result = divide(4,0); //调用divide()方法
System.out.println(result);
}
}
上面案例会产生一个ArithmeticException异常,这个异常只是java异常类中的一种,在Java中还提供了大量的异常类,这些类都继承自java.lang.Throwable类。
编译时异常、运行时异常
try ... catch和finally
异常捕获通常使用try...catch语句,其具体语法格式如下:
try {
//可能发生异常的语句
} catch (Exception 类或其子类 e) {
//对捕获的异常进行相应处理
}
案例:
public class Example29 {
//下面的方法实现了两个整数相除
public static int divide(int x, int y){
try {
int result = x/y; //定义一个变量result记录两个数相除的结果
return result; //将结果返回
}
}
}