面向对象_day04
学习目标:
1.关键字static
2.代码块
3.final
4.抽象类
5.接口
6.内部类
一、关键字static
1.1 static关键字的作用
在设计类的时候,我们常常希望将一些属性设置为多个对象共享的属性;例如设计中国人类,类中的属性国家名字 就要设计成多个对象共享的,因为不管创建多少个对象,对象的国家名字属性都是中国;例如设计圆类,类中的属性π 就要设计成多个对象共享的,因为不管半径多大的圆,π的值都是一样的;
static关键字就很好的解决了上述问题。被static修饰的成员在内存中只有一份,属于类的成员,在多个对象之间共享成员。
static 关键字的语法如下:
1.2 如何设置类属性和类方法
被static 修饰的属性成为类属性,被static修饰的方法为类方法。其类属性和类方法的设计过程如下:
- 类属性作为该类各个对象之间共享的变量。在设计类时,分析哪 些属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
- 如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
示例1:设计圆类
/**
* 设计圆类
*/
public class Circle {
//圆的π设计
private static double PI = Math.PI;
//设置圆的半径
private double radius;
//构造方法初始化圆
public Circle(double radius){
this.radius = radius;
}
//圆的面积方法
public double getArea(){
//return Circle.PI*radius*radius;
//在本类中调用静态属性和方法可以省略类名.。
return PI*radius*radius;
}
public static void main(String[] args) {
//创建圆对象,并获取面积
Circle circle = new Circle(5.5);
System.out.println(circle.getArea());
//创建另一个圆对象,并获取面积
Circle circle1 = new Circle(6.6);
System.out.println(circle1.getArea());
}
}
示例2:给数组排序,获取数组中最大值,最小值
/**
* 数组工具类,给数组排序,获取数组最大值,最小值
*/
public class MyArrays {
//给指定数组排序
public static void sort(int[] arr){
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
}
}
//计算数组中的最大值
public static int max(int[] arr){
int max = arr[0];
for(int i=1;i<arr.length;i++) {
if(max<arr[i]) {
max = arr[i];
}
}
return max;
}
//计算数组中的最小值
public static int min(int[] arr){
int min = arr[0];
for(int i=1;i<arr.length;i++) {
if(min>arr[i]) {
min = arr[i];
}
}
return min;
}
/*程序入口*/
public static void main(String[] args) {
//准备数组
int[] arr = {-1,11,3,9,5};
//排序
//MyArrays.sort(arr);
//本类访问静态访问可以省略类名.。
sort(arr);
for(int e : arr){
System.out.println(e);
}
//最大值
int max = max(arr);
System.out.println(max);
//最小值
int min = min(arr);
System.out.println(min);
}
}
注意: 在本类中访问静态方法或者静态属性可以省略类名.;
1.3 static关键字的修饰范围
在Java类中,可用static修饰属性、方法、代码块、内部类 ;代码块和内部类这里这是演示static可以修饰,第二章、第六章详细讲解
示例如下:
/**
* static关键字修饰范围
* 1.修饰属性:静态属性
* 2.修饰方法:静态方法
* 3.修饰代码块:静态代码块
* 4.修饰内部类:静态内部类
*/
public class StaticModifyScope {
//静态属性
static int i = 1;
//静态方法
public static void method(){
System.out.println("静态方法");
}
//静态代码块
static{
System.out.println("静态代码块");
}
//修饰内部类
static class innerClass{
}
}
1.4 被static修饰的成员特点
被static修饰的成员具有以下特点:
- 随着类的加载而加载
- 优先于对象存在
- 修饰的成员,被所有对象所共享
- 访问权限允许时,可不创建对象,直接被类调用
示例1:演示static修饰成员的特点:
/**
* static修饰类的成员特点:
* 1.随着类的加载而加载
* 2.优先于对象存在
* 3.修饰的成员,被所有对象所共享
* 4.访问权限允许时,可不创建对象,直接被类调用
*/
public class StaticDemo2 {
//静态属性
static int i = 1;
//静态方法
public static void method(){
System.out.println("静态方法");
}
public static void main(String[] args) {
//测试:随着类的加载而加,优先于对象存在
System.out.println(StaticDemo2.i);
StaticDemo2.method();
//测试:修饰的成员,被所有对象所共享
StaticDemo2 staticDemo2 = new StaticDemo2();
System.out.println(staticDemo2.i);
StaticDemo2 staticDemo22 = new StaticDemo2();
System.out.println(staticDemo22.i);
}
}
1.5 类变量内存图
1.4 节案例的内存结构如下;
结论:类加载到创建对象是有先后顺序的,顺序如下
- 在方法区加载类,加载静态成员且只有一份
- 在堆内存创建对象
- 在栈内存保留对象的内存地址
1.6 静态方法使用细节
静态方法在使用的时候需要注意如下细节:
- 在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构;这是因为先加载类方法,后创建对象的原因,既类方法加载完,对象方法还未必加载完。
- 普通方法体内可以调用被static修饰过得属性或者方法;这是因为先加载类方法,后创建对象的原因,普通方法加载完毕后,静态方法肯定加载完毕,所以能调用。
- 因为不需要实例就可以访问static方法,因此static方法内部不能有this。
- static修饰的方法不能被重写 ,因为static修饰的成员属于类,不属于对象
示例1:静态方法使用细节
public class StaticMethodDemo {
//静态属性
private static int i = 1;
//静态方法
public static void method1(){
//测试静态方法只能调用被static修饰的属性或方法
System.out.println(i);
//System.out.println(j); 报错
//method2(); 报错
System.out.println("静态方法");
}
//普通属性
private int j = 1;
//普通方法
public void method2(){
System.out.println("普通方法");
//普通方法即可以方法普通方法/属性又可以访问静态方法/属性
System.out.println(i);
System.out.println(j);
}
/*程序入口*/
public static void main(String[] args) {
StaticMethodDemo staticMethodDemo = new StaticMethodDemo();
staticMethodDemo.method2();
}
}
1.7 单实例设计模式
1.7.1 什么是设计模式?
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。
1.7.2 什么是单例设计模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构 造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生 类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
1.7.3 饿汉式单例设计模式
1.7.4 懒汉式单例设计模式
1.7.5 单例设计模式应用场景
单实例设计模式的应用场景如下:
-
网站的计数器,一般也是单例模式实现,否则难以同步。
-
应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
-
项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
-
Application 也是单例的典型应用
1.8 main方法
18.1 main 方法详细说明
由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。
18.2 main 方法参数设置
在main 方法中传入参数过程如下:
【1】run → edit configuration
【2】设置main 方法数组参数
1.9 总结
-
static基本用法
-
static修饰范围
-
static修饰变量内存结构
-
静态方法使用细节
-
单实例设计模式
-
main方法的理解以及传入参数
二、代码块
2.1 什么是代码块
代码块是类的成员 。通过{}或者 static{} 独立的一段代码程序。
作用:对Java类或对象进行初始化 。
代码块只能被static修饰; {} 这种事普通代码块 ,static{}这种是静态代码块。
2.2 普通代码块
普通代码块作用如下:
- 每次创建对象的时候,都会执行一次。且先于构造器执行。
- 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
- 一般用于对象的初始化功能,可以认为是对构造方法的补充,在构造方法运行前执行。
示例1:普通代码块应用
/**
* 普通代码块
*/
public class CodeBlockDemo {
private int id;
private String name;
//普通代码块
{
this.id = 1;
this.name = "张三";
System.out.println("对构造方法的补充,每执行一次构造方法就执行一次代码块,代码块在构造方法执行前执行");
}
public CodeBlockDemo() {
System.out.println("构造方法");
}
public static void main(String[] args) {
CodeBlockDemo codeBlockDemo = new CodeBlockDemo();
}
}
2.3 静态代码块
- 静态代码块随着类的加载而加载,且只执行一次
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 静态代码块一般用于驱动加载,加载配置文件等内容。
示例1:静态代码块的使用
/**
* 静态代码块
* 1. 静态代码块随着类的加载而加载,且只执行一次
* 2. 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
* 3. 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
* 4. 静态代码块一般用于驱动加载,加载配置文件等内容。
*/
public class StaticCodeBlockDemo {
static int i = 1;
static {
System.out.println("加载驱动或加载配置文件");
}
public static void main(String[] args) {
//通过调用静态属性,加载类,我发现静态代码块被最先加载起只加载一次。
System.out.println(StaticCodeBlockDemo.i);
}
}
三、关键字final
3.1 final 关键字概述
在Java中声明类、变量和方法时,可使用关键字final来修饰,表示“最终的”。
- final标记的类不能被继承。提高安全性,提高程序的可读性。
- String类、System类、StringBuffer类
- final标记的方法不能被子类重写。
- 比如:Object类中的getClass()。
- final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只能被赋值一次。
- final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋值,然后才能使用。
3.2 final 关键字使用
示例1:final修饰类
//被final修饰过的类不能有子类,不能被继承
public final class FinalDemo{
}
/*报错
* class Demo2 extends FinalDemo{
*
}*/
示例2:final修饰方法
public class FinalDemo2 {
public final void method1() {
}
}
class B extends FinalDemo2{
/*public final void method1() {报错
}*/
}
示例3:final修饰基本类型变量
public class FinalDemo3 {
public static void main(String[] args) {
//final修饰的变量是常量不能改变值
final int i = 1;
//i = 2;
}
}
示例4:final修饰引用类型变量
public class FinalDemo4 {
public static void main(String[] args) {
//final修饰的变量是常量,但是user值是内存地址,表示的是内存地址不能变化,对象内容可变。
final User user = new User(1,"小红");
user.setId(2);
user.setName("李四");
//改变地址报错
//user = new User(2,"李四");
}
}
class User{
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
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;
}
}
四、抽象类
4.1 为什么要有抽象类
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
4.2 抽象类的基本使用
抽象类的使用语法如下:
- 用abstract关键字来修饰一个类,这个类叫做抽象类;用abstract来修饰一个方法,该方法叫做抽象方法。
- 抽象方法:只有方法的声明,没有方法的实现。以分号结束: 比如:public abstract void talk();
- 含有抽象方法的类必须被声明为抽象类。
- 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
- 不能用abstract修饰变量、代码块、构造器、不能用abstract修饰私有方法、静态方法、final的方法、final的类。
- 抽象类也是类,类中能够定义的成员抽象类都能定义
示例1: 定义抽象类Person和子类Officer(官员)以及 Peasantry(农名)
//抽象类人
public abstract class Person {
//抽象方法说话
public abstract void speck();
/*程序入口*/
public static void main(String[] args) {
//创建抽象类对象,必须通过子类向上转型
Person person = new Officer();
person.speck();
Person person1 = new Peasantry();
person1.speck();
}
}
//官员类继承人类
class Officer extends Person{
@Override
public void speck() {
System.out.println("官员说话:字正腔圆,严谨无误");
}
}
//农民类继承人类
class Peasantry extends Person{
@Override
public void speck() {
System.out.println("农名说话:自由发言,无所顾虑");
}
}
4.3 模板设计模式
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
示例1:计算代码的运行时间
public abstract class CodeTemplate {
//计算某段代码执行所需要花费的时间
public void spendTime(){
long start = System.currentTimeMillis();
this.code();//不确定的部分、易变的部分
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
public abstract void code();
public static void main(String[] args) {
//测试代码花费时间
CodeTemplate codeTemplate = new SubTemplate();
codeTemplate.spendTime();
}
}
class SubTemplate extends CodeTemplate {
@Override
public void code() {
int sum = 0;
for(int i=1;i<=10000;i++){
sum+=i;
}
System.out.println(sum);
}
}
五、接口
5.1 接口概述
接口就是规范,定义的是一组规范,而不是实现这些规范的过程。例如:鼠标、键盘、打 印机、扫描仪等都支持USB连接;USB接口提出的就是一种规范,规范出这些设备的输入与输出接口USB;
java 中的接口也是这样,提出一组规范,告诉实现类如何按照规范实现这些接口;最终完成统一规范的编程,提高代码的规范性编程,提高代码的可读性。
由于java中的接口指定的是规范,所以接口中的方法都是抽象方法,接口中的属性都是公有静态常量。
另一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
5.2 接口的语法
jdk7 中的接口语法如下:
- 用interface来定义。
- 接口中的所有成员变量都默认是由public static final修饰的。
- 接口中的所有抽象方法都默认是由public abstract修饰的。
- 接口中没有构造器。
- 接口采用多继承机制。
- 创建接口的示例,只能根据接口的实现类创建
示例1:USB接口定义,与实例创建
/**
* 定义USB接口
*/
public interface USBInterface {
/**
* jdk1.7 接口
* 1.只能定义 公有的静态常量
* 2.只能定义公有抽象方法
*
*/
//1.公有静态常量
public static final String CODE = "矩形USB接口";
//2.默认公有静态常量
int DIAN_LIU = 5;
//3.公有抽象方法 输出电流
public abstract void out();
//4.默认公有抽象方法 输入指令
void input();
//5.不可以定义构造方法
//public USBInterface() {}
public static void main(String[] args) {
//1.向上转型创建实例
USBInterface shuBiao = new ShuBiao();
shuBiao.input();
shuBiao.out();
USBInterface jianPan = new jianPan();
jianPan.input();
jianPan.out();
}
}
class ShuBiao implements USBInterface {
@Override
public void out() {
System.out.println("输出鼠标左键右键指令");
}
@Override
public void input() {
System.out.println("输入"+USBInterface.DIAN_LIU+"电流");
}
}
class jianPan implements USBInterface {
@Override
public void out() {
System.out.println("输出键盘按键指令");
}
@Override
public void input() {
System.out.println("输入"+USBInterface.DIAN_LIU+"电流");
}
}
5.3 类、接口之间的相互关系
类与接口的关系,接口与接口的关系如下:
-
类与类之间是单继承,根类是Object;如 class A extends B {} B类默认继承了Object。
-
类与接口之间是多实现,一个类可以实现多个接口;如:class A implements C,D{};一个类可以同时继承一个类,然后实现多个接口;如:class A extends B implements C,D{ }
-
接口与接口之间是多继承;如: interface A extends C,D{}
其中在使用过程中需要注意以下几点:
- 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
- 接口的主要用途就是被实现类实现。(面向接口编程)
- 与继承关系类似,接口与实现类之间存在多态性
- 接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲, 接口是一种特殊的抽象类,这种抽象类中只包含常量和抽象方法的定义 (JDK7.0及之前)。
示例1:类、接口之间的关系
/**
* 类、接口之间的关系
*/
public class InterfaceDemo1 {
}
interface A {
}
interface A2{
}
// 类与接口之间是多实现
class B implements A,A2{
}
// 接口与接口之间是多继承
interface C extends A,A2{
}
5.4 jdk8 中 接口新增语法
Java 8中,你可以为接口添加静态方法和默认方法;在接口中静态方法一般实现类似工具类的功能,默认方法实现规范的默认实现。
静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。类似于工具类的用法
默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。 例如:java 8 API中对Collection、List、Comparator等接口提供了丰富的默认方法。
示例1:jdk8新增静态方法和抽象方法
public class InterfaceDemo2 {
public static void main(String[] args) {
//1.静态方法只可以通过接口名.静态方法
A.staticMethod();
//2.通过向上转型调用默认方法
A a = new B();
a.defaultMethod();
}
}
//1.jdk 1.8中 可以定义静态方法和默认方法
interface A {
public static void staticMethod() {
System.out.println("jdk1.8接口中可以定义静态方法,用法类似工具类静态方法");
}
public default void defaultMethod() {
System.out.println("jdk1.8中可以定义默认方法");
}
}
class B implements A{
// public void defaultMethod() {
// System.out.println("重写后的默认方法");
// }
}
注意
若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接 口时,会出现:接口冲突。
- 解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。
- 若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。
示例1:
public class InterfaceDemo3 {
public static void main(String[] args) {
A a = new C();
a.defaultMethod1();
}
}
interface A {
public default void defaultMethod1() {
System.out.println("默认方法");
}
}
interface B {
public default void defaultMethod1() {
System.out.println("默认方法");
}
}
class C implements A,B {
@Override // 当实现的两个接口有相同的默认方法,必须重写
public void defaultMethod1() {
System.out.println("必须重写默认方法");
}
}
示例2:
public class InterfaceDemo4 {
public static void main(String[] args) {
C c = new C();
c.defaultMethod1();
}
}
interface A {
public default void defaultMethod1() {
System.out.println("接口方法");
}
}
class B {
public void defaultMethod1() {
System.out.println("类方法");
}
}
class C extends B implements A {
}
5.5 静态代理设计模式
静态代理是非常常用的一种开发模式。既在不改变源代码的情况下,为一个功能类编写一个代理开发类,这个代理类会增加新的功能;
示例1:通过静态代理给用户的添加和删除功能加上日志功能
public class StaticProxyDemo {
public static void main(String[] args) {
User user = new UserImpl();
user.add("张三");
user.del("1");
User proxyUser = new UserProxy(user);
proxyUser.add("李四");
proxyUser.del("2");
}
}
//1.接口定义规范
interface User {
//1.添加用户数据
public void add(String data);
//2.根据id删除用户
public void del(String id);
}
//2.被代理类
class UserImpl implements User{
@Override
public void add(String data) {
System.out.println("添加"+data+"据");
}
@Override
public void del(String id) {
System.out.println("根据"+id+"删除数据");
}
}
//3.代理类
class UserProxy implements User{
private User user;
public UserProxy(User user) {
this.user = user;
}
@Override
public void add(String data) {
user.add(data);
System.out.println("日志信息");
}
@Override
public void del(String id) {
user.del(id);
System.out.println("日志信息");
}
}
5.6 工厂设计模式
我们在创建对象时不会对客户端直接暴露创建逻辑,而是 通过使用一个共同的接口根据不同的条件来指向具体想要创建的对象。
案例
/**
* 1.工厂设计模式
*/
//1.定义英雄规范
public interface Hero {
//1.购买英雄
public void buyHero();
//2.使用英雄
public void userHero();
public static void main(String[] args) {
Hero hero = HeroFactory.getHero("后裔");
hero.buyHero();
hero.userHero();
Hero hero2 = HeroFactory.getHero("程咬金");
hero2.buyHero();
hero2.userHero();
}
}
//2.定义具体英雄
class HouYi implements Hero{
@Override
public void buyHero() {
System.out.println("5000金币可以购买后裔");
}
@Override
public void userHero() {
System.out.println("攻速型射手");
}
}
//3.定义具体英雄
class ChengYaojin implements Hero{
@Override
public void buyHero() {
System.out.println("8800购买程咬金");
}
@Override
public void userHero() {
System.out.println("坦克回血");
}
}
//3.编写生产英雄工厂类
class HeroFactory{
public static Hero getHero(String name) {
if(name.equals("后裔")) {
return new HouYi();
}
if(name.equals("程咬金")) {
return new ChengYaojin();
}
return null;
}
}
5.7 小结
- 接口的基本使用
- jdk8接口新增方法
- 静态代理
- 工厂设计模式
六、内部类
6.1 内部类概述
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
内部类一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。内部类的名字不能与包含它的外部类类名相同;
6.2 内部类分类
内部类分类如下:
- 成员内部类
- 非静态成员内部类
- 静态成员内部类
- 局部内部类
- 局部内部类
- 匿名内部类
6.3 成员内部类
6.3.1 非静态成员内部类
非静态成员内部类,也是类的成员,使用语法如下:
- 非静态成员内部类可以被 访问权限修饰符修饰(private 默认 public protected)、也可以被final修饰,也可以被abstract修饰。
- 内部类可以定义属性、方法、以及构造方法
- 非静态成员内部类 不可以定义静态属性和静态方法
- 内部类支持继承
非静态成员内部类使用如法如下:
示例1:非静态成员内部类使用
/**
* 非静态成员内部类定义与使用
*/
public class OutsideClass {
//外部类成员属性
private int id = 1;
/**
* 1.非静态成员内部类也是类的成员可以被访问权限修饰符修饰、可以被final 、abstract修饰
* ;这些修饰父的作用和成员的变量、成员方法的修饰作用一样。
*/
public class InnerClass{
//定义内部类属性、方法、构造方法
private int id;
public void method(){
//调用内部类this
System.out.println(this.id);
//调用外部类this
System.out.println(OutsideClass.this.id);
System.out.println("内部类方法");
}
public InnerClass(){
System.out.println("内部类构造方法");
}
/**
* 报错:不可以定义静态变量和静态方法
*/
// private static int i ;
// public static void method2(){}
}
//内部类支持继承
public final class A extends InnerClass{
}
/*程序入口*/
public static void main(String[] args) {
//创建外部类对象
OutsideClass outsideClass = new OutsideClass();
//创建内部类对象
OutsideClass.InnerClass innerClass = outsideClass.new InnerClass();
innerClass.method();
}
}
6.3.2 静态成员内部类
静态成员内部类,也是类的静态成员,使用语法如下:
- 静态成员内部类被static修饰,同时可以被 访问权限修饰符修饰(private 默认 public protected)、也可以被final修饰,也可以被abstract修饰。
- 内部类可以定义属性、方法、以及构造方法
- 静态成员内部类 可以定义静态属性和静态方法
- 内部类支持继承
- 静态内部类不可以访问外部非静态属性、非静态方法。
静态成员内部类使用如法如下:
示例1:静态成员内部类使用
/**
* 静态成员内部类
*/
public class OutsideClass {
private int j = 1;
/*
* 1. 静态成员内部类被static修饰,同时可以被 访问权限修饰符修饰(private 默认 public protected)、也可以被final修饰,也可以被abstract修饰。
* 2. 内部类可以定义属性、方法、以及构造方法
* 3. 静态成员内部类 可以定义静态属性和静态方法
* 4. 内部类支持继承
* 5. 静态内部类不可以访问外部非静态属性、非静态方法。
* */
public static class InnerClass{
//定义属性、方法、构造方法
private int id;
public void method(){
System.out.println("普通方法");
}
public InnerClass(){
System.out.println("构造方法");
}
//定义静态属性和静态方法
private static int i = 1;
public static void method2(){
System.out.println("静态方法");
//静态内部类不可以访问外部非静态属性、非静态方法。 报错
// System.out.println(OutsideClass.this.j);
}
}
//内部类支持继承
class A extends InnerClass{
}
/*程序入口*/
public static void main(String[] args) {
//创建内部类对象
OutsideClass.InnerClass innerClass = new OutsideClass.InnerClass();
innerClass.method();
//调用内部类静态方法
OutsideClass.InnerClass.method2();
}
}
6.4 局部内部类
编写在在方法内、代码块内、构造方法内的类,称之为局部内部类;局部内部类分为匿名内部类和普通局部内部类。
6.4.1 匿名内部类
匿名内部类是一种特殊的局部内部类,它的作用在于可以直接创建接口和抽象类实例,也可以直接创建一个父类的子类实例;其语法固定,格式如下:
示例1:根据匿名内部类创建接口/抽象类实例
/**
* 匿名内部类演示:
*/
public class InnerClassDemo2 {
public static void main(String[] args) {
//根据匿名类创建抽象类实例
Animal animal = new Animal() {
@Override
void eat(String food) {
System.out.println("吃的是:"+food);
}
};
animal.eat("肉");
//根据匿名类创建接口实例
USB usb = new USB() {
@Override
public void useUSB() {
System.out.println("接口的使用规范实现");
}
};
usb.useUSB();
}
}
abstract class Animal{
abstract void eat(String food);
}
interface USB{
public void useUSB();
}
6.4.2 局部内部类
普通局部内部类语法如下:
- 局部内部类可以定义在 方法内 代码块 构造方法内
- 局部内部类不可以用任何修饰符修饰,只可以被final修饰;局部内部类和局部变量地位类似,不能使用public,protected,缺省,private;局部内部类不能使用static修饰,因此也不能包含静态成员
- 局部内部类可以定义成员属性和方法以及构造方法。
- 局部内部类只可以在内部定义内部使用。但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的生命周期不同所致。jdk1.8以后不用加final,这是语法糖,不写也有
示例1:局部内部类演示
/**
* 局部内部类演示
*/
public class InnerClassDemo3 {
private int id;
//在方法内部定义局部内部类
/*
1. 局部内部类可以定义在 方法内 代码块 构造方法内
2. 局部内部类不可以用任何修饰符修饰,只可以被final修饰
3. 局部内部类可以定义成员属性和方法以及构造方法。
4. 局部内部类只可以在内部定义内部使用。但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
5. 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。jdk1.8以后不用加final
6. 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
7. 局部内部类不能使用static修饰,因此也不能包含静态成员
*/
public Animal method1(){
final class Tiger extends Animal{
private int id;
private String name;
public Tiger(int id,String name){
this.id = id;
this.name = name;
}
}
Tiger tiger = new Tiger(1,"百兽之王");
return tiger;
}
}
class Animal{
}
6.5 小结
- 成员内部类
- 非静态成员内部类应用
- 静态成员内部类应用
- 匿名内部类
七、面向对象大总结
7.1 类的成员
答:类的成员包括:成员变量、普通方法、静态方法、构造方法、代码块、静态代码块、成员内部类。
public class 类名{
1.成员变量/属性/字段
2.普通方法
3.静态方法
4.构造方法
5.代码块
6.静态代码块
7.成员内部类
}
7.2 关键字总结
7.2.1 访问权限修饰符
答:修饰类的访问权限修饰符有:默认(缺省)和public;被public 修饰的类可以在任意包访问,默认修饰的类只能在本包访问。
修饰成员属性、成员方法、构造方法,成员内部类的修饰符有:private、默认、protected、public ;被private修饰的成员只能在本类访问、被默认修饰的成员只能在本包访问、被protected修饰的成员能在不同包的子类实例中访问、被public修饰的成员能在任意包任意类访问。
修饰代码块的修饰符只有static,既静态代码块。
7.2.2 this与super关键字
答:this关键是这个的含义,表示当前对象的引用;this可以用在普通方法和构造方法中,在普通方法中可以调用当前对象的属性和方法,既this.属性、this.方法();在构造方法中可以调用当前对象的其他构造函数、属性、方法,既this.属性、this()构造函数、this.方法();若调用构造函数,必须写在第一行。
super关键是父类的含义,表示当前实例父类实例的引用;super可以用在普通方法和构造方法中,在普通方法中可以调用父类的属性和方法,既super.属性、super.方法();在构造方法中可以调用父类的构造函数、属性、方法,既super.属性、super()构造函数、super.方法();若调用构造函数,必须写在第一行;即便不写,在子类构造函数中也默认存在super()构造函数,创建子类实例必须先创建父类实例。
7.2.3 final 关键字
答:final关键字可以修饰变量、方法、类;修饰变量代表常量,修饰方法代表最终方法不能被重写,修饰类代表最种类不能被继承。
7.2.4 static 关键字
答:被static修饰的成员在内存中只有一份且随着类的加载而加载,static可以修饰变量、方法、代码块、内部类;
7.3 封装与javaBean
答:javaBean是可重用组件;必须私有字段,公有setter、getter方法,有公有无参数构造方法。
7.4 重载与重写
答:重载是指在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可;方法的重载与返回值类型无关,只看参数列表,且参数列表必须不同。
重写:重写发生在子父类之中,指的是子类覆盖父类的方法。
- 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表 、方法返回值
- 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限
- 子类不能重写父类中声明为private权限的方法
- 子类不能重写父类中声明static的方法,因为static的方法属于类,不属于对象。
- 子类方法抛出的异常不能大于父类被重写方法的异常
- 可以通过@Override注解检查是否是重写(只是测试是否是重写,可以不写,可以写)
7.5 多态
答:多态是指对象或方法的多种形态:既编译形态和运行形态。例如:List list = new ArrayList();
编译时是list类型,运行时是ArrayList类型;多态有两种表现形式:向上转型和方法的重写。
7.6 单实例设计模式
答:保证对象只有一份,私有构造方法,通过静态方法获得单实例对象。代码参照课上。
7.7 模版设计模式
答:模版设计模式是基于抽象类的设计模式,既抽象类抽取抽象的模版方法,子类根据模版实现方法的过程。
7.8 工厂设计模式
答:工厂类的静态方法根据不同的条件生成不同实例的过程。
7.9 静态代理设计模式
答:静态代理是指代理类实现目标类的功能并添加额外的功能;实现过程是和目标类实现同一个接口,然后在代理类中注入目标类,先调用目标类的方法,在然后在扩展新的功能。
7.10 抽象类
答:被abstract修饰的类是抽象类,普通类里能够定义的成员,抽象类里都能定义,抽象类还可以定义抽象方法。不能直接创建抽象类实例,必须让子类重写抽象类的全部抽象方法,才能通过子类创建抽象类实例。
7.11 接口
答:接口代表的是规范;接口只能有公有静态常量和抽象方法;jdk8以后可以在接口中定义静态方法和默认方法。