java基础8【抽象类、接口、内部类,包,垃圾回收,Lambda,类类型转化】

abstract - 抽象类
  • 如果一个类的所有子类都对这个类中的某个方法做了重写,那么这个时候这个类中的对应的方法可以不定义方法体,需要用abstract修饰方法,从而成为了一个抽象方法。
  • 抽象方法所在的类必须是抽象类。— 抽象类中不一定有抽象方法
  • 抽象类不能创建对象
  • 抽象类一定不是最终类
  • 注意:任何一个类都有构造方法
  • 抽象方法没有方法体,一定要被重写。
  • 抽象方法可以定义被static/final/private修饰吗?—不行
  • Static修饰的不能被重写!叫隐藏
  • 抽象方法一定不能定义在最终类中。
  • 如果一个类中的抽象方法用的是默认权限,对子类有什么要求?— 要求父子类要同包
  • 子类如果不是抽象类,子类继承抽象类之后,必须重写父类的抽象方法,是的话,可以不重写。
  • 抽象类中可以定义一切方法,包括抽象方法,普通方法,构造方法(子类创建对象的时候会用到)!
  • 抽象类中如果有抽象方法,子类不是抽象类,子类要重写父类所有抽象方法,所以父类抽象类一定不定用final修饰!
  • 抽象方法没有方法体,所以一定要被重写,才有意义!
  • abstract修饰的是抽象方法
interface — 接口

目录,再往上一拉

  • 接口中定义都是抽象方法(JDK1.8以前)。
  • 作用:作为模板或者是协议、约束等来使用。
  • 在JDK1.8以前,接口中只能定义抽象方法 — 默认用public abstract修饰。接口中可以定义属性但是默认使用public static final修饰。从JDK1.8开始,接口中允许定义实体方法,必须用default修饰,也可以定义静态方法。
  • 类和接口之间用的是implements关键字来产生关联 — 实现。类在实现接口之后需要重写接口中所有的抽象方法
  • 接口不允许被实例化,也没有构造方法
  • 在Java中,支持的是类和接口之间的多实现 — 一个类可以实现多个接口
  • 在Java中,支持接口之间的多继承
  • 接口是用 接口.属性/方法 来进行调用
  • JDK1.8
  • 把只有一个抽象方法的接口,称为函数式接口@FunctionalInterface
  • 允许使用静态方法,实体方法
// 如果一个接口中只定义了一个抽象方法,那么把这个接口声明为函数式接口
// 函数式接口用@FunctionalInteface
@FunctionalInterface
interface Calc {
//抽象方法没有方法体
	public double add(double i, double j);

	// 接口中的默认方法(实体方法) --- 默认是public
	public default double max(double i, double j) {
		return i > j ? i : j;
	}
//静态方法
	public static double min(double i, double j) {
		return i < j ? i : j;
	}

}

内部类

目录,再往上一拉

局部/方法内部类
  • 定义在方法中的类 — 方法/局部内部类 – - 为了重复使用某段逻辑,并且使这段逻辑只从属于某一个方法使用
  • 方法内部类只能在定义他的方法中使用!
  • 当方法内部类使用所在的方法中的数据的时候,要求这个属性必须是一个常量,但从JDK1.8开始,方法内部类使用到当前方法中的数据的时候,会将该数据默认为常量,称为常量的隐式声明
    -方法内部类只能在定义它的方法中使用
  • 可以使用外部类中的属性和方法
  • 如果内部类和外部类存在了同名属性或者方法,则使用内部类中定义,就近原则,如果要调用外部类的,需用 外部类.this.方法名/属性
  • 方法内部类只能用abstract/final
  • 方法内部类中可以定义非静态的属性和非静态方法,但是不能定义静态变量和静态方法,但可以定义静态常量
  • 从这几个点思考: 对象(地址)、存储/执行、生命周期(作用范围)
成员内部类
  • 可以使用外部类中的属性和方法
  • 可以定义非静态属性和非静态方法 ,但是不能定义静态变量和静态方法 然而定义静态常量
定义在类中类
Outer2.Inner2 oi2 = new Outer2().new Inner2();
静态内部类

目录,再往上一拉

  • 用static修饰的内部类
  • 静态内部类可以用abstract修饰!
  • 只能使用外部类中的静态属性和静态方法,静态内部类中可以定义一切的方法和属性
  • 就处在成员位置上,跟静态方法类似,只不过是
Outer3.Inner3 oi3 = new Outer3.Inner3();
匿名内部类

目录,再往上一拉

  • 匿名内部类本质上是实现了对应的接口或者是继承了对应的类
  • 任何一个接口都可以存在匿名内部类形式
  • 一个类只要可以被继承,那么就可以存在匿名内部类形式 — 最终类不存在匿名内部类形式
  • 扩展:类中可以定义类,类中也可以定义接口,接口中可以定义类,接口中也可以定义接口 —
    如果类中定义了接口或者是接口中定义了接口,那么称之为内部接口 — 类中定义的接口,以及接口中定义的类和接口默认都是静态的
class A {
static interface A1 {}
}  
interface B {
static class B1 {}
static interface B2{}
}

目录,再往上一拉

  • 声明包用的是package — 区分同名类,进行功能的划分
  • 导入包用的是import — 导包的作用是用于提示代码从哪儿去找这个类
  • " * " 通配符 ---- 表示导入当前包下的所有的类但是不包括子包下的类
  • java — 原生包 javax — 扩展包
  • org — 第三方厂商提供的一些常用的包
  • java.lang -核心/基本包,包含了Java程序运行需要的基本类。在Java程序启动的时候,包下的类就已经自动加载到内存中,所以使用的时候可以不用导包
  • java.util - 工具包 java.math - 数学运算 java.io - 数据传输 java.net - 网络通信
    java.nio - 高并发 java.text - 格式化
  • 总结:java.lang包下的类以及子包类在使用的时候可以不用导包
垃圾分代回收机制

目录,再往上一拉

  • 针对的是堆内存。
  • Java中的每种数据类型大小都是确定的,所以所有的内存是由Java自己进行分配,意味着内存的管理和回收也是由JVM自己进行—在Java中一旦产生内存问题导致程序员无法处理。理论上在正常情况下Java中的堆内存是足够使用的
    — 当堆内存使用的负荷量(一般情况下70%)超过一定限度的时候,会启动垃圾回收器(Garbage Collector — GC)进行堆内存的回收释放
    Heap space
      Young Generation
        eden
        survivor
          from space
          to space
      Old Generation
    扩展:eden:from:to = 8:1:1
  • 对象刚创建的时候是先放入新生代中的伊甸园区;如果在伊甸园区经过一次回收依然存在,那么将这个对象挪到幸存区,在幸存区中经过多次回收这个对象依然存在则挪到老生代。在回收的时候先回收新生代,如果新生代回收之后的内存足够使用则不扫描老生代;如果不够则扫描老生代。老生代的扫描频率要低于新生代
  • 发生在新生代的回收 — 初代回收 minor gc
  • 发生在老生代的回收 — 完全回收 full gc
  • 扩展:对象创建完成之后会先试图放入新生代;如果新生代经过回收之后也放不开,则直接试图将该对象放入老生代。老生代如果也放不开,则会出现错误— OutOfMemoryError
Lambda

目录,再往上一拉

package cn.tedu.lambda;
public class LambdaDemo {
	public static void main(String[] args) {
		// 接口中只定义了1个抽象方法
		// 可以利用Lambda表达式来重写这唯一的一个抽象方法
		// Calc c = new Calc() {
		//
		// @Override
		// public double add(double i, double j) {
		// return i + j;
		// }
		//
		// };
		// 表示重写Calc中的唯一的一个抽象方法add
		// Lambda表达式只能作用在函数式接口上
		// Calc c = (double a, double b) -> {
		// return a + b;
		// };
		// 方法体只有一句,可以省略{}和return不写
		// 唯一的一句方法体的计算结果默认为当前方法的返回值
		// Calc c = (double i, double j) -> i + j;

		// 重写的是Calc接口中的方法add
		// add方法的参数列表的类型是已知的
		// 可以省略参数类型不写
		// 函数式编程
		Calc c = (x, y) -> x + y;

		System.out.println(c.add(5.8, 9.47));

	}

}

interface Calc {

	double add(double i, double j);

}
更简化Lambda表达式

目录,再往上一拉

package cn.tedu.lambda;

public class LambdaDemo2 {

	public static void main(String[] args) {

		// 方法体只有1句
		// 这一句方法体是直接操作参数
		// 这一句方法体是调用了已有类Math中的静态方法sqrt
		// 参数列表可以省略
		// Calculator c = d -> Math.sqrt(d);
		Calculator c = Math::sqrt;
		System.out.println(c.sqrt(9));

	}

}

interface Calculator {

	double sqrt(double d);

}
小知识
  • API — Application Programming Interface — 应用程序接口 — 接口以及实现类

局部 / 方法内部类 例子
目录,再往上一拉

package exer1;


public class InnerDemo1 {

	public static void main(String[] args) {

		new Outer1().m();

	}

}

class Outer1 {

	int i = 10;

	public void m() {
		System.out.println("Outer~~~");

		// 当方法内部类使用所在的方法中的数据的时候
		// 要求这个属性得是一个常量
		// 从JDK1.8开始,方法内部类使用到当前方法中的数据的时候
		// 将该数据默认为常量
		// 常量的隐式声明
		int j = 10;

		// 方法内部类
		// 只能在定义它的方法中使用
		// 可以使用外部类中的属性和方法
		// 如果内部类和外部类存在了同名属性或者方法,则使用内部类中定义
		// 方法内部类只能用abstract/final
		// 方法内部类中可以定义非静态的属性和非静态方法
		// 但是不能定义静态变量和静态方法
		// 然而定义静态常量
		class Inner1 extends Object implements Cloneable {

			int k = 8;
			static final int x = 7;

			public void m() {
				System.out.println("Inner~~~");
				i += 5;
				m2();
				// 外部类.this.外部类的方法或者属性
				Outer1.this.m2();
				System.out.println(j);
				// j += 6;
				System.out.println(k + 1);
				System.out.println(x);
			}
			public void m2() {
				System.out.println("Inner m2~~~");
			}
		}

		Inner1 i1 = new Inner1();
		i1.m();
	}

	public void m2() {
		System.out.println("Outer m2~~~");
	}

}
成员内部类—例子

目录,再往上一拉

package cn.tedu.innerclass;

public class InnerDemo2 {

	public static void main(String[] args) {

		// Outer2 o2 = new Outer2();
		// System.out.println(o2.i);
		// o2.m();
		Outer2.Inner2 oi2 = new Outer2().new Inner2();
		System.out.println(oi2.j);

	}

}

class Outer2 {

	public int i = 3;

	 Inner2 i2 = new Inner2();

	// 成员内部类
	// 可以使用外部类中的属性和方法
	// 可以定义非静态属性和非静态方法
	// 但是不能定义静态变量和静态方法
	// 然而定义静态常量
	class Inner2 {

		int j = 10;
		static final int k = 8;

		public void m() {
			i += 3;
			Outer2.this.m();
		}

	}

	public void m() {
		System.out.println("Outer");
	}

}
匿名内部类 — 例子

目录,再往上一拉

package cn.tedu.innerclass;

public class InnerDemo4 {

	public static void main(String[] args) {

		// 匿名内部类
		// a是匿名内部类产生的对象
		// 匿名内部类实际上是实现了对应的接口
		A a = new A() {

			@Override
			public void m() {
				System.out.println("running~~~");
			}

			@Override
			public void m2() {

			}
		};
		a.m();
		// 匿名内部类实际上是继承了对应的类
		B b = new B() {

			@Override
			public void m() {
				System.out.println("running~~~");
			}
		};
		b.m();

		// C c = new C() {
		// };
	}

}

interface A {

	void m();

	void m2();
}

abstract class B {

	public abstract void m();
}

final class C {
}
类型转化 — 自动转/强转

目录,再往上一拉

package cn.tedu.interfacex;

public class InterfaceDemo2 {

	public static void main(String[] args) {

		// A a = new B1();

		// 在Java中支持的是类和类之间的单继承
		// 所以此时会形成一棵继承结构树
		// 所以比较容易的就能确定两个类之间是否有继承关系
		// 因此在进行强制转换的时候
		// 会检查要转换的对象的声明类和转换的类型是否有继承关系
		// a对象的声明类型是A类,要转换的类型是B1
		// B1继承了A,所以在编译时期就不报错
		// 到了运行的时候才会检查对象的实际类型和要转换的类型是否一致
		// 运行的时候,发现a的实际类型是B1,要转换的类型是B1
		// 类型一致,允许转换
		// B1 b1 = (B1) a;

		// a对象的声明类型是A类,要转换的类型是B2
		// B2继承了A,所以在编译时期就不报错
		// 到了运行的时候,a的实际类型是B1,要转换的类型是B2
		// 类型不一致,所以报错 --- ClassCastException
		// B2 b2 = (B2) a;

		// b1对象的声明类型B1类,要转换的是B2
		// B2没有继承B1,编译就不通过
		// B2 b2 = (B2) b1;

		// C c = (C) a;

		// 在Java中,类和接口之间是多实现,接口和接口之间是多继承
		// 所以构成了一张图状结构 --- 网状结构
		// 不容易确定两个节点之间的关系
		// 因此在编译时期为了提高效率放弃检查(不会报编译错误)
		// 直到运行的时候再确定类型是否相同
		// D d = (D) a;

		// C c = new C();
		// D d = (D) c;

	}

}

class A {
}

class B1 extends A {
}

class B2 extends A {
}

class C {
}

interface D {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值