javaSE(基础四) 面向对象(五)
jdk1.8新增接口特性
可以在接口中定义带有方法体的方法:
1)静态方法: 根据接口名使用
2)默认方法: 根据实现类
public interface Demo{
//静态方法
public static void testStatic(){
System.out.println("我是静态方法");
}
//默认方法
default void test(){
System.out.println("我是默认方法");
}
}
练习
/*
电脑使用外接UDB设备
电脑 USB 外接设备 鼠标 键盘 ...
*/
public class Computer {
//开机
void open(){
System.out.println("开机");
}
//***使用USB设备 参数为接口类型 :实现类USB接口的设备 都能当做实参传递
void useUSB(USB m){
if(m!=null){
m.start();
m.end();
}else{
System.out.println("设备坏啦");
}
}
//关机
void close(){
System.out.println("关机");
}
}
public class KeyBoard implements USB{
@Override
public void start() {
System.out.println("开始使用键盘");
}
@Override
public void end() {
System.out.println("结束使用键盘");
}
}
public interface USB {
//开始
void start();
//结束
void end();
}
public static void main(String[] args) {
Computer com = new Computer();
KeyBoard kb = new KeyBoard();
//引用
kb = null;
com.open();
com.useUSB(kb);
com.close();
com.useUSB( new USB() {
@Override
public void start() {
}
@Override
public void end() {
}
});
}
}
//总结:可以将接口类型当做参数传递,可以new USB()接口对象,实现接口中的抽象方法,然后将new USB()接口对象当做参数传给useUSB()方法使用,不用引用名接收,只用一次.
内部类
概念:在类中定义类,当类中的成员也是一种事物时,可以把这个成员定义为内部类
成员内部类
概念:内部类作为外部类的成员,就称为成员内部类
成员内部类既有成员的特点,又有类的特点:
1)可以被成员修饰符进行修饰: 权限修饰符 static final …
2)类可以被继承,实现…
定义:成员内部类中静态的内容不能定义,除了静态常量
static final int A = 5; //可以定义
public static int b = 15;//报错,不能定义静态内容,只能定义静态常量
private int c = 20;
使用:
1)在成员内部类中可以直接使用外部类中的成员,包括私有的
2)使用内部类中的成员要通过内部类对象使用,包含私有的
3)其他类中使用内部类中的成员,需要通过外部类对象构建内部类对象,使用内部类的成员
//3)例子
Outer outer = new Outer(); //Outer 外部类
Outer.Inner inner = outer.new Inner(); //Inter 内部类
//上面两步的简化代码
Outer.Inner inner2 = new Outer().new Inner();
练习:区分同名问题
public class OuterTest02 {
private int i = 1;
class Inner{
int i = 5;
public void inner(){
int i = 10;
System.out.println(i); //局部i = 10
System.out.println(this.i); //内部类的成员i = 5
System.out.println(OuterTest02.this.i); //外部类的成员i = 1
}
}
}
//总结:可以通过外部类类名.this.成员进行调用
私有内部类
使用:
1)在私有内部类中可以直接使用外部类中的成员,包含私有成员
2)在外部类中可以通过私有内部类中的对象直接使用私有内部类中的成员,包含私有
3)在其他类中无法使用私有内部类
4)可以间接使用私有内部类中的私有成员,可以作为外部类方法的参数返回
public class Outer03 {
//私有成员变量
private int i = 1;
//私有内部类
private class Inner{
//私有内部类的私有成员
private String a = "私有内部类的私有成员";
private void inner(){
System.out.println(i);
}
}
public void outer(){
Inner in = new Inner();
System.out.println(in.a);
in.inner();
}
}
//4)作为外部类方法的参数返回
class A{
public String show(Outer03.Inner in){
return in.a;
}
}
静态内部类
使用:
1)静态内部类中的定义静态内容,可以定义成员
2)在内部类中可以直接使用外部类中的静态内容,如果想要使用外部类中的成员内容,通过外部类对象使用
public class Outer{
int j = 10;
static class Inner{
System.out.println(new Outer().j);
}
}
局部内部类:
使用:
1)只能在所定义的方法中使用
2)如果局部内部类中使用所在方法的参数,默认被final修饰(java7手动添加final,java8之后默认final)
public class Outer05 {
static int a = 123;
public static void main(String[] args) {
}
void outer(final int args){
//局部
int i =1;
//局部内部类
class Inner{
//局部内部类成员变量
String str = "局部内部类成员变量";
void inner(){
System.out.println(i);
System.out.println(a);
System.out.println(args);//outer(final int args)中final可以省略
}
}
***匿名内部类
定义:没有名字的内部类,直接以接口名或者抽象类名创建对象
作用:用来简化没有太多作用功能的实现类|子类
当只需要使用一次(次数很少)某接口中的方法时,使用匿名内部类可以不用创建类实现接口,然后通过类对象.重写方法区去使用功能,简化了代码. 直接将接口作为引用类型创建对象
使用:
1):创建没有名字的实现类对象,只在当前行使用一次,后续无法继续使用
interface Run{
void run();
}
new Run(){ //Run实现类的类体,只不过这个实现类没有名字
@Override
public void run() {
System.out.println("变跑变傻笑...");
}
}.run(); //将new Run()作为对象.run()进行调用
2):引用指向匿名内部类对象,后续可以多次使用
interface Swin{
void swimming();
void drink();
}
Swim swim = new Swim(){
@Override
public void swimming() {
System.out.println("蛙泳...");
}
@Override
public void drink() {
System.out.println("...");
}
};
swim.swimming();
swim.drink();
3):匿名内部类做参数传递
test(new Swim() {
@Override
public void swimming() {
}
@Override
public void drink() {
}
});
//将匿名内部类作为test()方法的参数
匿名内部类实现抽象类:
public class Outer07 {
public static void main(String[] args) {
//目的: 想要使用一下抽象方法absMethod
//方式: 定义一个子类继承AbsClass 抽象类,重写抽象方法,才能通过子类对象调用
//问题: 子类没有类本身自己的作用,就是为了重写抽象方法
//可以使用匿名内部类简化,匿名内部类是类,只是没有名字 ,作用域在当前类中
//new的是AbsClass的一个匿名的子类对象
AbsClass abs = new AbsClass(){
@Override
void absMethod() {
System.out.println("哈哈哈");
}
};
abs.absMethod();
}
}
abstract class AbsClass{
abstract void absMethod();
}
总结
1)内部类可以使用外部类的成员,外部类使用内部类中的内容需要通过内部类中的对象调用
2)静态内容不能调用非静态内容,非静态可以调用静态
lambda jdk8新特性
**目的:**为了简化大量使用匿名内部类,jdk8提供了简化匿名内部类的表达式
**前提:**函数性接口
函数性接口:只有一个必须要被重写的抽象方法的接口
检查函数性接口的注解:@FunctionalInterface
语法: ()->{}
(): 重写的抽象方法的参数列表
->: lambda符号,箭头符号
{}: 重写抽象方法的方法体
注意:lambda体重写哪一个接口的抽象方法,看前面的引用
使用:
public class LambdaDemo {
public static void main(String[] args) {
//匿名内部类
Smoke s = new Smoke() {
@Override
public void smoking() {
System.out.println("小岳岳式吸烟吗...");
}
};
//1.简化匿名内部类
s = ()->{
System.out.println("边吸烟边敲代码...");
};
s.smoking();
//A demo = ()->{};
//2.如果lambda中的方法体{}中语句体只有一句,前后的{}可以省略
//demo = ()->System.out.println("123");
//3.如果抽象方法的有形参,参数的数据类型可以省略
//A demo = (int x,int y)-> System.out.println(x+y);
//A demo = (x,y)-> System.out.println(x+y);
//4.如果抽象方法的有形参,并且参数只有一个,前后()可以省略
//A demo = i-> System.out.println(i);
//5.如果语句体只有一句,并且是return语句. 则前后{}和return都可以省略
A demo = i-> {
return i>100;
};
demo = i->i>100;
System.out.println(demo.a(1));;
}
}
//
@FunctionalInterface
interface Smoke{
void smoking();
default void test(){}
}
interface A{
boolean a(int x);
}
数组
一维数组
定义:相同数据类型的数据的有序集合
特点:
1)引用数据类型[] 2)数据类型相同 3)数组的长度一旦确定,不可改变 4)有序,从0开始,一段连续的内存空间
公式: 数据类型[] 数组名 = new 数据类型[长度];
练习
package com.xxxx.array05;
import java.util.Random;
/*
随机点名器
存储班级所有同学的相关信息
*/
public class ByName {
public static void main(String[] args) {
//1.构建班级学生
Student s1 = new Student(101,"陈振洪",21);
Student s2 = new Student(102,"陈振坤",22);
Student s3 = new Student(103,"陈洁",18);
Student s4 = new Student(104,"陈真",30);
//2.构建存储学生的数组
/*Student[] arr = new Student[4];
arr[0] = s1;*/
Student[] arr = {s1,s2,s3,s4};
//3.定义随机数 数组长度为4,索引变化范围[0,3]
//num数组的索引
int num = new Random().nextInt(4);
//4.随机点名
System.out.println(arr[num]);
}
}
class Student{
private int id;
private String name;
private int age;
public Student() {
}
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
/*总结:1)将学生对象作为数据存储在数组中,数组的数据类型就为Student类型
2)使用系统自动生成的带参构造器,方便设置值
3)重写toString()方法,方便输出
4)Random ran = new Random();
int num = ran.nextInt(4); 下面是简化写法
int num = new Random().nextInt(4);
*/
二维数组
二维数组: 数组中放数组
声明: 数据类型[][] [][] [] [] 数组名;
数据类型: 由内层小数组中存储的数据类型决定
初始化:
先创建数组后赋值
数据类型[] [] 数组名 = new 数据类型[一维数组的长度] [二维数组的长度];
数据类型[] [] 数组名 = new 数据类型[一维数组的长度] [ ] ;
//创建数组的同时赋值
数据类型[] [] 数组名 = new 数据类型[] [] {{数据1,数据2…},{},{}…};
操作二位数组:
数组名[外层数组的索引] [内层数组的索引]
二位数组的遍历:
双重循环嵌套(任意嵌套:普通for 和for_each)
//数组的遍历:
//1)增强for嵌套增强for
for(int[] a:arr){
for(int i:a){
System.out.println(i);
}
}
//2)普通for嵌套普通for
//i外层数组索引
for(int i = 0;i<arr.length;i++){
//j内层数组索引
for(int j=0;j<arr[i].length;j++){
System.out.println(arr[i][j]);
}
}
//3)普通for嵌套增强for
for(int i=0;i<=arr.length-1;i++){
for(char ch:arr[i]){
System.out.println(ch);
}
}
//4)增强for嵌套普通for
for(String[] ar:arr2){
for(int i=0;i<ar.length;i++){
System.out.println(ar[i]);
}
}