JavaSe基础:面向对象4
1. 接口interface
接口使用interface关键字定义,接口是一种类似规范的东西,需要通过implements关键字实现,接口有以下特点:
- 是一个特殊的抽象类
- 是一个引用数据类型
- 类只能单继承,接口是多实现
- 是方法(抽象方法)的集合
接口使用的注意点:
- 接口需要被类实现
- 接口中一般都是大量的抽象方法,实现后重写方法才可以使用
- 实现与继承非常像,都能够有权使用接口/父类中的成员/功能,但是侧重点不一样
- 接口中不能定义普通的方法,大部分为抽象方法
- 接口不能实例化
- 一个类可以同时继承父类,并且实现多个接口,先继承后实现
- 接口不能实现接口,接口只能继承接口,可以多继承
1.1 jdk1.7及之前
jdk1.7版本及之前接口中只能定义以下两种类型:
-
公共的静态的常量,具体语法:
public static final 数据类型 常量名 = 赋值;
其中public,static,final都可以省略
-
公共的抽象的方法,具体语法:
public abstract 返回值类型 方法名(参数列表);
其中public,abstract都可以省略
例:
//测试接口
public class TestInterface {
public static void main(String[] args) {
InterfaceDemo im = new InterfaceDemo();
im.haha();
im.hehe();
im.heihei();
}
}
//定义A接口
interface A{
//定义抽象方法
void haha();
}
//定义B接口
interface B{
//定义抽象方法
void hehe();
}
//定义C接口继承A,B接口
interface C extends A,B{
//新增抽象方法
void heihei();
}
//定义类实现接口C
class InterfaceDemo implements C{
//重写接口C继承的接口A中的抽象方法
@Override
public void haha() {
System.out.println("haha");
}
//重写接口C继承的接口B中的抽象方法
@Override
public void hehe() {
System.out.println("hehe");
}
//重写接口C新增的抽象方法
@Override
public void heihei() {
System.out.println("heihei");
}
}
1.2 jdk1.8及之后
jdk1.8版本及之后新增两种可以写在接口中的方法:
- 静态方法:但是只能通过接口名使用,实现类对象不能使用
- 默认方法:通过实现类对象使用默认方法
例:
//测试2种可以带方法体的方法
public class TestInterface02 {
public static void main(String[] args) {
//通过接口名使用接口中的静态方法
infa.study();
//通过实现类对象使用接口中的默认方法
new ShiXianLei().play();
}
}
//定义接口infa
interface infa{
//定义静态方法
static void study(){
System.out.println("我在学习");
}
//定义默认方法
default void play(){
System.out.println("我在玩耍");
}
}
//定义类实现infa接口
class ShiXianLei implements infa{
}
2. 内部类
内部类是在类中定义类,当一个类中的成员也是一个事物时,这个成员就可以定义为内部类。
内部类分为以下五种类型:
2.1 成员内部类
成员内部类有以下特点:
- 一个类作为另外一个类的成员
- 拥有成员与类的特性
- 成员内部类中不可以定义静态内容,除了静态常量
- 成员内部类中可以使用外部类中的所有成员,包括私有的
- 在外部类中可以通过内部类的对象使用内部类中的成员,包括私有的
- 其他类中使用成员内部类中的内容,需要通过外部类对象构建内部类对象,通过内部类对象使用内部类中的成员
例:
//测试成员内部类
public class TestInner {
public static void main(String[] args) {
//创建外部类对象
Outer out = new Outer();
System.out.println(out.a);
//调用外部类的成员方法
out.outerMethod();
//定义内部类对象***
Outer.Inner in = out.new Inner();
//调用内部类的成员方法
in.innerMethod();
}
}
//定义外部类
class Outer{
int a = 10;
//定义内部类
class Inner{
String name = "张三";
//内部类方法
public void innerMethod(){
//可直接使用内外部类的成员变量
System.out.println(a);
System.out.println(name);
System.out.println("我是内部类的方法");
}
}
//外部类方法
public void outerMethod(){
System.out.println(a);
//生成内部类对象使用内部类成员变量
System.out.println(new Inner().name);
System.out.println("我是外部类的方法");
}
}
2.2 私有内部类
私有内部类即被private关键字修饰的成员内部类,特点如下:
- 在外部类中通过私有内部类的对象使用成员
- 在内部类中可以直接使用外部类中的成员,包含私有的
- 私有的内部类只能在当前的外部类中使用
2.3 静态内部类
静态内部类即被static关键字修饰的成员内部类,特点如下:
- 静态内部类中可以定义静态内容,其他成员内部类中不可以定义静态内容吗,除了静态的常量
- 静态内部类也是静态的内容,想要使用成员就需要通过对应类型的对象调用其成员
- 在其他类中使用静态内部类中的静态内容,要通过外部类名.静态内部类名.静态内容调用静态内容
- 在其他类中使用静态内部类中的成员内容,要通过new 外部类名.静态内部类名()的对象调用成员
2.4 局部内部类
局部内部类有以下特点:
- 不能使用public,static等修饰符修饰,final可以
- 如果在局部内部类中使用当前方法中的局部变量,默认被final修饰(jdk8开始默认,jdk7及之前必须手动添加final)
- 局部内部类中的内容只有在当前方法中通过局部内部类的对象使用其成员
例:
public class Outer05 {
void test(int args){
//局部
int i = 1;
//局部内部类
class Inner extends Object{
public int a = 5;
static final int b = 10; //静态常量
void test(){
System.out.println("局部内部类中的成员方法");
System.out.println(i);
System.out.println(args);
}
}
new Inner().test();
System.out.println( new Inner().a);
}
}
2.5 匿名内部类
匿名内部类是用来简化实现类/子类的,因为接口或者抽象类中可能存在抽象方法,必须在实现类/子类中重写。
创建一个匿名内部类对象的语法:
new 接口名|抽象类名() {
匿名内部类的类体;
}
例:
//测试匿名内部类
public class Outer05 {
public static void main(String[] args) {
//1.匿名对象: 只能在当前行使用一次
new Play(){
@Override
public void play() {
System.out.println("打篮球");
}
}.play();
//2.当前作用域中可使用多次的匿名内部类对象,通过接口类型的引用指向
Play p = new Play() {
@Override
public void play() {
System.out.println("踢足球");
}
};
//可多次调用方法
p.play();
p.play();
//3.匿名内部类对象作为方法的参数
new Outer05().test(new Play() {
@Override
public void play() {
System.out.println("玩电脑");
}
});
}
//定义方法
void test(Play p){
p.play();
}
}
//定义接口
interface Play{
void play();
}
3. Lambda表达式
jdk1.8版本新增了一个特性即lambda表达式,目的是为了简化匿名内部类对象。
lambda表达式的前提是必须为函数式接口,函数式接口是只有一个必须被重写的抽象方法的接口,在开发工具中可通过@FunctionalInterface检查接口是否为函数式接口。
lambda表达式的结构:( )->{ }
- ( ):重写的抽象方法的参数列表
- ->:箭头函数,具有上下文推导的作用
- { }:重写的抽象方法的方法体
lambda表达式有以下几种写法,通过代码进行说明:
//测试lambda表达式
public class LambdaTest {
public static void main(String[] args) {
//写法1:普通写法
Play p1 = () -> {
System.out.println("踢足球");
};
p1.play();
//写法2:当接口抽象方法的方法体语句只有一句的时候,前后的{}可以省略
Play p2 = () -> System.out.println("踢足球");
p2.play();
//写法3:抽象方法有参数,参数的数据类型可以省略
Study s1 = (a) -> System.out.println("学习java");
s1.study(5);
//写法4:抽象方法的形参只有一个,前后的()可以省略
Study s2 = a -> System.out.println("学习java");
s2.study(5);
//写法5:抽象方法有返回值类型,方法的语句体只有一个,且是return语句的时候,前后的{}与return关键字可以一起省略
Sleep sl1 = ()->"返回值";
System.out.println(sl1.sleep());
}
}
//定义Play接口
interface Play{
void play();
}
//定义Study接口
interface Study{
void study(int a);
}
//定义Sleep接口
interface Sleep{
String sleep();
}