面向对象高级编程 全课程

文章目录

序章 课程内容总览

在这里插入图片描述

第一章 面向对象编程基础

引入

面向对象的历史。

类与对象

类(class)是对象(object)的设计图纸,定义了对象的数据结构和操作。

封装

程序结构

在这里插入图片描述

类结构

在这里插入图片描述

类结构与封装

在这里插入图片描述

变量与数据类型

在这里插入图片描述

变量访问与生存期

在这里插入图片描述
局部变量:method()里的 int n = 0;
对象成员变量:double v1 = 100;
类成员变量:static int V = 100;
在这里插入图片描述

为什么class中变量用private?方法用public?——封装性的强化

public class circle()
{
	private double radius;
	
	public circle(double radius)
	{
		this.setradius(radius);
	}
	public double getradius()
	{
		return radius;
	}
	public void setradius()
	{
		this.radius = radius;
	}
}
补充知识:Java内存管理

在这里插入图片描述

类的实例化

在这里插入图片描述

函数

在这里插入图片描述

函数的参数传递

值传递。
值的两种类型:原始类型和引用类型。
在这里插入图片描述

函数重载

在这里插入图片描述

字符串

在这里插入图片描述

标准输入输出

在这里插入图片描述

public class Test{
public static void main(String[] args)
{
	Scanner input = new Scanner(System.in);
	System.out.print("输入信息:")String s = input.next();
	System.out.println("打印信息:"+ s);
}
标准输入流

System.in为标准输入流,需要联合Scanner类一起使用。
Scanner sc = new Scanner(System.in);
Scanner类提供了多种读取的方式:nextInt读取下一个整数,nextLine读取下一行等。
注意:因为此种输入方式是可见的,所以Scanner类不适用于从控制台读取密码。Java6特别引入了Console类来实现这个目的。

import java.util.Scanner; // 需要导入 util 包

Scanner input = new Scanner(System.in);
String str1 = input.next();
String str2 = input.nextLine(); // 获取字符串
int number1 = input.nextInt(); // 获取整数
float number2 = input.nextFloat(); // 获取浮点数据

//循环输入
while (input.hasNextInt()) {
	int tmp = input.nextInt();
}
System.out.println(tmp); // 与println效果相同
input.close(); // 掉用完成关闭方法


next() 与 nextLine()的区别

next()
一定要读取到有效字符后才可以结束输入。
对输入有效字符之前遇到的空白,next()方法会自动将其去掉。
只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
next()不能得到带有空格的字符串。
nextLine()
以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符。
可以获取到空白。

输出流

1、标准输出流
最常用的就是标准输出流
System.out.println();

2、格式化输出
除此之外,还可以格式化输出。Java5沿用了C语言函数库中的printf方法。
System.out.printf("%8.2f",x);

文件输入输出

想要读取一个文件,需要构造一个Scanner对象
Scanner in = new Scanner(Path.of("myfile.txt"),StandardCharsets.UTF_8);
如果想写入一个文件,则需要构造一个PrintWriter对象
PrintWriter out = new PrintWriter("myfile.txt",StandardCharsets.UTF_8);
对于这种相对文件名的方式指定的,其实际位置位于Java虚拟机启动目录的位置。
需要注意的是,访问不存在的文件或写入的文件名不合规则会抛出异常。

控制流

在这里插入图片描述

数组

在这里插入图片描述

for-each 循环

for-each循环是Java相比C语言中的for循环拓展而来的一种新的遍历数组的循环方式。for-each循环通过对数组内元素类型相同的变量进行遍历,直接数组内从下标为0的位置至最后一个位置的元素的元素值。

for-each循环基本语句

for ( 变量类型  变量名 : 数组名 ) {
    
    需要执行的循环语句;
 
}

示例

int [] a = new int [10];
 
//for循环遍历
 
for ( int i=0 ; i<10 ; i++ )
    a[i];
 
//for-each循环遍历
 
for ( int k : a);

实例

import java.util.Scanner;
 
public class Main {
 
	public static void main(String[] args) {
		
		int [] data = {56, 75, 68, 45, 24, 245, 2, 5, 22, 27, 5};
		int x = 0;
		Scanner in = new Scanner ( System.in );
		x = in.nextInt();
		
		boolean found = false;
		for ( int k : data ) {
			if ( k==x ) {
				found = true;
				break;
			}
		}
		
		if ( found )	
			System.out.println("找到了");
		else 	
			System.out.println("没找到");
		
		in.close();
	}
 
}

继承关系

在这里插入图片描述

继承与复用

在这里插入图片描述
Java只支持单继承。
B继承A后,可以调用A的方法。

在这里插入图片描述
不能,找不到这个按键了(没有高级功能)。

子类实例化

在这里插入图片描述

接口与多态

在这里插入图片描述

使用interface的方法,抽象类中的抽象函数实质上也是属于接口范畴。
在这里插入图片描述

泛型与类型安全

泛型编程是JAVA 5加入的特征,实现代码中类型参数化的功能。
在这里插入图片描述

泛型的引入

Java泛型的应用可以提高代码的复用性,同时泛型提供了类型检查,减少了数据的类型转换,同时保证了类型的安全。下面来看一下,泛型如何保证了类型的安全:

  List list = new ArrayList();
 
    list.add("abc");
 
    list.add(new Integer(1)); //可以通过编译
 
    for (Object object : list) {
 
           System.out.println((String)object);//抛出ClassCastException异常
 
    }

上面的代码会在运行时抛出ClassCastException,因为它尝试将一个Integer转换为String。接着,来看一下从java5开始,Collection的用法:

 List<String> list = new ArrayList<>();
 
 list.add("abc");
 
 //list.add(new Integer(1)); //编译错误
 
 for (String string : list) {
 
      System.out.println(string);//无需任何强制类型转换
 
 }

注意到,List的创建增加了类型参数String,因此只能向list添加String类型对象,添加其他对象会抛出编译异常;同样可以注意到,foreach循环不需要再添加任何强制类型转换,也就移除了运行时的ClassCastException异常。

泛型类与接口

既然是学泛型,自然就要知道如何去使用泛型定义自己的类和接口。同时为了加深理解泛型的作用,我们先定义一个不适用泛型的类:

public class Gen {
 
     private Object obj;
 
     public Object getObj() {
 
        return obj;
 
     }
 
     public void setObj(Object obj) {
 
        this.obj = obj;
 
     }
 
     public static void main(String[] args) {
 
        Gen gen = new Gen();
 
        gen.setObj("abc");
 
        String str = (String) gen.getObj();//类型转换,可能会引起运行时ClassCastException
 
       }
 
}

原始类的定义,容易引发ClassCastException,因为在使用的时候我们无法知道具体的类型到底是什么。现在来看一下泛型类来重新定义Gen — 使用<>指定泛型参数,如下:

public class Gen<T> {
 
T obj;
 
public T getObj() {
 
return obj;
 
}
 
public void setObj(T obj) {
 
this.obj = obj;
 
}
 
public static void main(String[] args) {
 
Gen<String> gen = new Gen<>();
 
gen.setObj("abc");
 
// gen.setObj(10); //无法通过编译
 
String str = gen.getObj(); //无需类型转换
 
//-----------------------------
 
Gen gen2 = new Gen();//raw type原始类型
 
gen2.setObj("abc");
 
gen2.setObj(10); //可以通过编译,自动装箱将10转化为Integer对象
 
Integer num = (Integer) gen2.getObj();//使用了强制类型转换
 
}
 
}

main()方法里是使用泛型类型Gen,便不再需要强制类型转换,也就移除了运行时的ClassCastException。同时为了区别,在此也定义了一个没有使用泛型类型的gen2,这时,编译器会弹出一个警告“Gen is a raw type,References to generic type Gen should be parameterized”。当我们不提供泛型类型时,会默认使用Object会代替,也是因此这样,gen2可以设置String和Integer类型,不过,我们应尽量去避免这种这种情况的出现,如此,便又需要用到强制类型转换,也伴随着运行时的ClassCastException异常。

可以使用@SuppressWarnings(“rawtypes”)来忽略编译器弹出警告。

接口的泛型应用和类的泛型应用非常类似:

public interface List <E> {
 
 void add(E x);
 
 Iterator<E> iterator();
 
}
 
 
 
public interface Iterator<E> {
 
 E next();
 
 boolean hasNext();
 
}

另外,在定义泛型类和泛型接口的时候,我们也可以定义多个泛型化参数。例如Java中的Map<K,V>。

泛型类的使用

在使用泛型类的时候,我们就需要将泛型参数具体化,例如:

public static void main(String[] args) {
 
ArrayList<String> list = new ArrayList<>();
 
list.add("ABC");
 
list.add(123);//报错!由于泛型已经具体化成String类型,就不能使用整数类型了
 
}

需要注意的是,当我们将泛型参数具体化成String类型之后,原本ArrayList中的add(E e)方法的参数类型就会变成String类型,这时候在调用add()方法的时候,就只能传入String类型的参数了。

另外,在Java中明确的规定了泛型参数在具体化的时候只能使用引用类型,所以是有的泛型参数必须使用Object类型及其子类类型,如果使用基本类型,就会出错:

//这里不能使用基本类型来具体化泛型参数
 
ArrayList<int> list = new ArrayList<>();

泛型类的继承和泛型接口的实现

我们在实现泛型接口的时候,也必须要定义泛型类去实现泛型接口。例如:

public class ArrayList<E> implements List<E>{
 
 
 
}
泛型的命名规范

为了更好地去理解泛型,我们也需要去理解java泛型的命名规范。各种常用泛型参数的意义如下:

E — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>

K,V — Key,Value,代表Map的键值对

N — Number,数字

T — Type,类型,如String,Integer等等

S,U,V etc. - 2nd, 3rd, 4th 类型,和T的用法一样。
泛型方法与构造方法

有些时候,我们可能并不希望将整个类都泛型化。这个时候我们就可以只在某个方法上定义泛型,构造方法也是一样。例如:

public class GenMethod {
 
    public static <T> void fromArrayToCollection(T[] a,Collection<T> c){
 
        for (T t : a) {
 
              c.add(t);
 
        }
 
    }
 
    public static void main(String[] args) {
 
        Object[] oa = new Object[100];
 
        Collection<Object> co = new ArrayList<>();
 
        GenMethod.<Object>fromArrayToCollection(oa, co);
 
   }
 
}

定义方法所用的泛型参数需要在修饰符之后添加,如上面的,public static ,如果有多个泛型参数,可如此定义<K,V>或者<T1,T2>。

泛型的继承与子类型

如果两个类之间有继承被被继承的关系,那么我们就可以将一个类的对象赋值类另外一个类的对象,比如:

String str = new String();
 
Object obj = new Object();
 
obj = str;

这种关系同样适用于泛型。比如我们将泛型参数设置为Number,那么在随后的调用中,就只需要传入一个Number类型或者是Number的子类类型的对象就行了,比如Integer,Float,Double都可以:

ArrayList<Number> list = new ArrayList<>();
 
list.add(new Integer(1));
 
list.add(new Float(1.0));
 
list.add(new Double(1.0));

但是有一种情况是我们需要特别注意的,比如我们定义一个如下的方法:

public void someMethod(ArrayList<Number> n) {
 
}

这个方法能接受什么样类型的参数类?

ArrayList?
ArrayList?
ArrayList?

显然ArrayList。
原因是:虽然Integer和Double是Number类型的子类,但是ArrayList和ArrayList类型并不是ArrayList类型的子类。

在泛型里也存在子类型,前提是其泛型参数的限制并没有发生改变,或者说泛型没有改变。其实就是从原来的类或接口来判断泛型的子类型。

比如ArrayLIst implements List,而List extends Collection,那么ArrayList就是List的子类型,而List又是Collection的子类型。

泛型参数界限与通配符

有时候,你会希望泛型类型只能是某一部分类型,比如在操作数据的时候,你希望是Number或其子类类型。这个通常的做法就是给泛型参数添加一个参数。其定义的形式为:

<T extends ParentType>

这个定义表示T应该是Numner的子类型,T和Parant可以是类,也可以是接口,注意此处的extends表示的是ParentType的子类型,和继承是有区别的。

public class Box<T> {
 
    private T t;
 
    public void set(T t) {
 
        this.t = t;
 
    }
 
    public T get() {
 
        return t;
 
    }
 
    public <U extends Number> void inspect(U u) {
 
        System.out.println("T: " + t.getClass().getName());
 
        System.out.println("U: " + u.getClass().getName());
 
    }
 
    public static void main(String[] args) {
 
        Box<String> integerBox = new Box<>();
 
        integerBox.set("abc"); //能通过编译,因为T指定为String类型
 
        // integerBox.inspect("abc");//不能通过编译,因为U必须是Number类型或其子类
 
        integerBox.inspect(new Integer(10));
 
    }
 
}

对象关系

关联

在这里插入图片描述

组合

在这里插入图片描述

聚合

在这里插入图片描述

依赖

在这里插入图片描述

其他特征

原始类型的装箱和拆箱

什么是装箱?什么是拆箱?

Java为每种基本数据类型都提供了对应的包装器类型。
在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行:

Integer i = new Integer(10);

而在从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:

Integer i = 10;

这个过程中会自动根据数值创建对应的 Integer对象,这就是装箱。

那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型:

Integer i = 10;  //装箱
int n = i;   //拆箱

简单一点说,装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型。

1、实体中数值类型一般定义为包装类型
2、接受参数推荐定义为包装类型
目的:避免null导致程序异常。

装箱和拆箱是如何实现的
public class Main {

    public static void main(String[] args) {
        Integer i = 10;
        int n = i;
    }
}

装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。

在这里插入图片描述

为什么使用ArrayList< Integer >?

集合元素不支持原始数据类型:ArrayList< int >,需要修改为ArrayList< Integer >。

final类是什么?

在这里插入图片描述
包装类为final类型,表示该类不能被继承(扩展)。
被包装的值value为final类型,表示初始化后不能被修改,这种类也称为immutable.

在这里插入图片描述

枚举类

在这里插入图片描述
参考博文:https://blog.csdn.net/zhou520yue520/article/details/80952404

内部类与匿名类(迭代器)

在这里插入图片描述

lambda表达式
在这里插入图片描述

反射与动态编程

在这里插入图片描述

第二章 面向对象设计思想——设计原则与设计模式

设计原则

在这里插入图片描述

其他原则

关注点分离在这里插入图片描述
抽象原则

在这里插入图片描述
在这里插入图片描述

SOLID

职责分配原则

创造者模式

单例模式

原型模式

实验2 设计小游戏让人物跑起来

结构型模式

适配器模式

实验3 动图字幕编辑器

代理模式(动态代理)

实验6 带日志功能的计算器

行为型模式

状态模式

实验4 角色状态控制

职责链模式(迭代器)

实验5 基于职责链的计算器
实验5 支持迭代访问的整型列表

观察者模式

实验7 环境监控程序

第三章 Java核心技术

实验8 多线程与网络编程
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值