1. 抽象类
1.如果一个类中,有抽象方法的话,那么这个类必须定义为抽象类
抽象类格式:
abstract class类名{}
抽象方法格式:
权限修饰符 abstruct 返回值类型 方法名(参数列表);
2.抽象类的本质:强制子类重写抽象方法
3.抽象类的特点:
1.抽象类不能实例化,但是抽象类一定存在最具体的子类,否则没有意义
2.抽象类中可以没有抽象方法(抽象类中没有抽象方法的意义:不能实例化)
4.抽象类的实例化
通过抽象类多态,父类引用指向子类对象,有最具体的子类
5.抽象类的成员特点:
(1)成员变量:可以是变量,也可以是自定义常量
(2)成员方法:既可以是抽象方法(必须有abstract),也可以是非抽象方法
(3)构造方法:存在继承关系,子类继承父类,分层初始化
6.abstract不能与那些关键字一起使用:
(1)private:被private修饰的方法只能在当前类访问,而abstract需要子类重写
(2)final:final关键字修饰的方法不能被重写
(3)static:与类相关,随着类的加载而加载,而抽象方法需要被子类重写,最终需要使用对象来抽象化多态:Fu fu = new Zi();和static一起使用在父类中没有方法体,加载没有意义
2. 接口
1.接口是一种规范,就是能实现接口中的额外功能
接口比抽象类还抽象的一种类型
2.格式:
interface 接口名(大驼峰命名法){}
class 子实例类名 implements 接口1,接口2...{}
接口名 对象名 = new 子实例类名();
3.接口中的方法只能是抽象方法,不能有方法体
特点:不能实例化,通过接口多态,所以具有具体的子类
4.接口中的成员特点:
(1)成员变量只能是常量,存在默认修饰符: public static final(可以省略不写)
(2)接口中的构造方法:没有构造方法
(3)接口中的成员方法:只能是抽象方法,存在默认修饰符:public abstract(可以省略不写)
// 默认方法,必须有方法体,接口自己的默认方法
default void 方法名(){
System.out.println("method Inter...");
}
//静态方法
public static void 方法名(){
System.out.println("function Inter...");
}
5.关系的区别
(1)类与类的关系:继承关系
(2)类与接口关系:实现关系
一个类继承自另一个类的时候,可以实现多个接口
(3)接口与接口的关系:可以单继承,多继承,多层继承
3.形式参数问题
方法的形式参数:基本数据类型/引用数据类型
1.形参为基本数据类型,实际参数就是当前的数据值就行,而且形参的改变不会影响实际参数
2.形参为引用数据类型(空间地址值的传递)
(1)具体类:实际参数应该创建当前具体类对象
class Student{
public void study(){
sout("学习Java");
}
}
class StudentDemo{
public void method(Student student){
student.study();
}
}
class 测试类{
main(){
StudentDemo student = new StudentDemo();
Student a = new Student();
student.method(a);
sout("========================");
student.method(new Student());
sout("========================");
new StudentDemo.method(new Student());
}
}
(2)抽象类:实际参数传递时创建当前抽象类的子类对象(抽象类多态)
abstract class Student{
public abstract void study();
}
}
class Students extends Student{
public void study(){
sout("学习java");
}
}
class StudentDemo{
public void method(Student student){
student.study();
}
}
class 测试类{
main(){
StudentDemo student = new StudentDemo();
Student a = new Students();
student.method(a);
sout("========================");
student.method(new Students());
sout("========================");
new StudentDemo.method(new Students());
}
}
(3)接口:传递接口实现类的对象
interface Student{
public abstract void study();
}
class Students implements Student{
public void study(){
sout("学习java");
}
}
class StudentDemo{
public void method(Student student){
student.study();
}
}
class 测试类{
main(){
StudentDemo student = new StudentDemo();
Student a = new Students();
student.method(a);
sout("========================");
student.method(new Students());
sout("========================");
new StudentDemo.method(new Students());
}
}
(4)数组:实际参数传递数组对象
import java.util.Arrays;
class Array{
public void array(int[] arr){
sout(Arrays.toString(arr));
}
}
class ArrayTest{
main{
Array a = new Array();
int[] arr1 = new int[4];
a.array(arr1);
}
}
4. 返回值类型问题
返回值类型:基本数据类型/引用数据类型
1.返回值为基本数据类型,直接返回基本数据类型的返回值即可
2.返回值类型为引用数据类型
(1)具体类:需要返回当前类的具体对象
class Student{
public void study(){
sout("学习java");
}
}
class StudentDemo{
public Student method(){
return new Student();
}
}
class 测试类{
main(){
StudentDemo a = new StudentDemo();
Student b = a.method();
b.study();
sout("=============================");
new StudentDemo.method().study();
}
}
(2)抽象类:返回当前抽象类的子类对象
abstract class Student{
public abstract void study();
}
class Students extends Student{
public void study(){
sout("学习java");
}
}
class StudentDemo{
public Student method(){
return new Students();
}
}
class 测试类{
main(){
StudentDemo a = new StudentDemo();
Student b = a.method();
b.study();
sout("=============================");
StudentDemo a = new StudentDemo();
a.method().study();
sout("=============================");
new StudentDemo.method().study();
}
}
(3)接口:需要返回子实现类的对象
interface Student{
public abstract void study();
}
class Students implements Student{
public void study(){
sout("学习java");
}
}
class StudentDemo{
public Student method(){
return new Students();
}
}
class 测试类{
main(){
StudentDemo a = new StudentDemo();
Student b = a.method();
b.study();
sout("=============================");
StudentDemo a = new StudentDemo();
a.method().study();
sout("=============================");
new StudentDemo.method().study();
}
}
5.内部类
1.内部类:
(1)成员内部类:在外部类的成员位置定义的类
(2)局部内部类:在外部类的成员方法中定义的类
(3)静态内部类
2.访问成员问题
(1)成员内部类:(前提:当前的成员内部类是非静态的)
(可以用private修饰,保证数据安全)
可以访问外部类的所有成员,外部类也可以访问内部类的变量和方法
创建内部类对象的方法格式:
外部类名.内部类名 对象名 = new 外部类名().new内部类名();
class Outer{
private String name = "张三";
int age = 14;
//内部类
class Inner{
int n = 10;
public void show(){
sout(name+age+n);
}
}
//外部类成员方法
public void method(){
Inner inner = new Inner();
inner.show();
}
}
class 测试类{
main(){
Outer outer = new Outer();
outer.method();
}
}
(2)局部内部类:局部内部类可以访问外部类所有成员,但是局部内部类的成员只能在创建该局部类的方法中调用
面试题:局部内部类访问局部变量的时候,能访问码?局部变量有什么要求?
jdk7或者jdk7以前,局部变量必须显示加入final修饰,否则访问报错
而jdk8已经jvm优化了,此时这个num2就是常量!---使用反编译工具查看内部类的结构--->发现其实已经加入了final
局部变量的生命周期是随着的方法的调用而存在,随着方法的调用结束而消失;
而当前这个方法结束之后,num2局部变量也应该就不存在了,但是我们还在使用内部类对象访问它里面这个成员方法,而对象不会立即被GC立即回收,等待空闲的时候回收没有更多引用的对象,所以此时这些变量应该都是常驻内存,使用final定义----->常量!
class Outer4{
private int num = 100 ;//外部类的成员变量
//成员方法
public void method(){
//局部内部类
class Inner4{
//成员方法
public void show(){
//局部变量
int num2 = 20 ;
//局部内部类访问局部变量--->能访问吗?
// --->此时这个变量有什么要求吗?--有
System.out.println(num2) ;// 没有报错!
System.out.println(num) ;//访问外部类的成员
}
}
//在method方法中,访问show
//创建局部内部类对象.show()
Inner4 inner4 = new Inner4() ;
inner4.show() ;
}
}
//测试类
public class InnerClassDemo4 {
public static void main(String[] args) {
//创建外部类对象
Outer4 outer4 = new Outer4() ;
outer4.method() ;
}
}
(3)静态内部类:用static修饰的成员内部类
静态内部类只能访问外部类的静态成员,外部类访问静态内部类时,可以跳过外部类直接通过内部类访问静态内部类成员
创建静态内部类对象的格式:
外部类名.静态内部类名 变量名 = new 外部类名.静态内部类名();
5.权限修饰符和包
1.
同类中 相同包不同类 不同包的子类 不同包的无关类
private √
default √ √
protected √ √ √
piblic √ √ √ √
2.static在工具类中将构造方法私有化,里面方法加入static,类名访问
3.包-----就是文件夹
真实的开发环境中包需要针对代码分层
代码分包:
(1)实体类--存储实体类(描述现实世界事物的)
com.qf.pojo/entity/domain
//属性私有化,对外提供get/set方法
(2)service层--业务接口层
com.qf.service
举例:UserService //用户注册功能
boolean register(User user) ;
boolean login(User user) ;
com.qf.service.impl--业务接口的实现
UserServiceImpl实现上面的这些功能
数据从数据库中访问
在业务实现层中调用数据库访问层中的接口方法
(3)持久层(数据库访问层)
com.qf.dao
UserDao接口
数据访问的接口层//查询数据库中是否有User信息
boolean sleectUser(User user)
com.dao.impl
UserDaoImpl实现层
数据访问接口实现层
boolean sleectUser(User user) {}
(4)控制层 controller层
com.qf.controller
类名:UserController
代码--->调用业务层数据方法
就有业务数据--->利用前后端的交互技术
进行数据的视图的渲染!
4.带包的编译运行
(1)手动方式:
创建com文件夹
子文件夹qf
使用javac对源文件编译
将字节码文件放在qf子文件夹下
带包名运行
java 包名.字节码文件前缀
(2)自动方式
javac -d . java文件-->自动产生文件夹和字节码文件
带包运行即可
6 匿名内部类
1.没有名字的类
2.使用场景:很少有为具体类的匿名内部类,因为具体类本身就可以new对象
一般都是抽象类和接口中使用最多
3.格式:
//(一般是抽象类名或者接口类名)
new 类名(){
重写抽象类或者接口的抽象方法{
}
};------------->不能忘记分号
4.本质:就是继承了该抽象类或者实现了接口的子类对象
6.1实操代码
1.有以下代码可看出
(1)使用常规方法我们需要写一个接口实现类,重写接口方法之后去调用方法
(2)使用匿名内部类不需要写接口实现类,直接采用匿名方式去调用方法
interface Inter{
void show();
void show2();
}
//定义一个外部类
class Outer{
public void method(){
//1.常规用法
class InterImpl implements Inter{ //访问方式为在方法体后.方法名
public void show(){
System.out.println("这是一个接口实现类");
}
public void show2(){
System.out.println("这是一个接口实现类");
}
}
class Demo{
public void show3(Inter j){
j.show();
j.show2();
}
}
Demo demo = new Demo();
Inter inter = new InterImpl();
demo.show3(inter);
//2.采用匿名内部类
//访问方式为在方法体后.方法名
new Inter(){
public void show(){
System.out.println("这是一个匿名内部类");
}
public void show2(){
System.out.println("这是一个匿名内部类");
}
}.show();
new Inter(){
public void show(){
System.out.println("这是一个匿名内部类");
}
public void show2(){
System.out.println("这是一个匿名内部类");
}
}.show2();
//以上访问方式代码量过大,创建一个接口对象来接收
Inter i = new Inter(){
public void show(){
System.out.println("这是一个匿名内部类");
}
public void show2(){
System.out.println("这是一个匿名内部类");
}
};
i.show();
i.show2();
}
}
//测试类
public class InnerClassTest{
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
输出结果:
这是一个接口实现类
这是一个接口实现类
这是一个匿名内部类
这是一个匿名内部类
这是一个匿名内部类
这是一个匿名内部类
6.2 当方法的形式参数为接口类(抽象类相同)
1.方法的形式参数如果是一个接口类型,调用方法的时候,需要传递接口的子实现类对象
interface Inter{
void show();
void show2();
}
//定义一个类,实现接口的方法
class InterDemo{
public void method(Inter inter){
inter.show();
inter.show2();
}
}
//测试类
public class InnerClassTest{
public static void main(String[] args) {
//创建方法对象
InterDemo demo = new InterDemo();
demo.method(new Inter(){
@Override
public void show() {
System.out.println("这是形式参数为接口类的方法");
}
@Override
public void show2() {
System.out.println("这是形式参数为接口类的方法");
}
});
}
}
输出结果:
这是形式参数为接口类的方法
这是形式参数为接口类的方法
6.3方法返回值为接口(抽象类相同)
1.方法的返回值如果是一个接口,需要接口的子实现类对象
interface Inter{
void show();
void show2();
}
//定义一个类,实现接口的方法
class InterDemo {
public Inter method() {
return new Inter() {
@Override
public void show() {
System.out.println("这是返回值为接口的匿名对象");
}
@Override
public void show2() {
System.out.println("这是返回值为接口的匿名对象");
}
};
}
}
//测试类
public class InnerClassTest{
public static void main(String[] args) {
//创建方法对象
InterDemo demo = new InterDemo();
demo.method().show();
demo.method().show2();
System.out.println("========================");
Inter inter = demo.method();
inter.show();
inter.show2();
}
}
输出结果:
这是返回值为接口的匿名对象
这是返回值为接口的匿名对象
========================
这是返回值为接口的匿名对象
这是返回值为接口的匿名对象
6.4 拉姆达表达式
1.JDK8之后,当接口中只有一个抽象方法的时候,那么这个接口可以称为"函数式接口"
interface Love{
void love() ;
}
class LoveDemo{
public void show(Love l){//方法的形式参数是一个接口--->需要接口的子实现类对象
l.love();
}
}
//测试类
public class InnerClassTest2 {
public static void main(String[] args) {
//访问的是LoveDemo中的show方法
LoveDemo ld = new LoveDemo() ;
//当接口中有且仅有一个抽象方法的时候,那么这个接口可以称为"函数式接口"
//函数式接口---->实现方法的时候---->有一个 -> 箭头直接可以实现接口的方法
ld.show( //接口的匿名内部类很多
() ->{
System.out.println("爱生活,爱Java,爱高圆圆");
}
) ;
}
}
6.5匿名类面试题
* 看程序,补全代码--->控制台输出"hello world"
* 考点匿名内部类的使用
interface Inter{
void show() ;
}
class Outer{
//以下为补全代码
public static Inter method(){
return new Inter(){
public void show(){
sout("hello world");
}
};
}
}
public class Test {//测试类
public static void main(String[] args) {
Outer.method().show();
//分析思路-->Outer能够直接访问method,说明method是一个静态方法-->能够直接访问show方法,说明是有返回值
}
}