1、包
- 进行面对对象的编程时,一项最基本的考虑是:如何将发生变化的东西与保持不变的东西分隔开,这一点对于库来说是非常重要的。那个库的用户必须能依赖自己使用的那部分。如何将组件绑定到单独统一的库单元里。这是通过Java中的关键字package(打包)来实现的。
- 我们用import关键字导入一个完整的库时,就会获得“包”(Package)
例如:import java.util.*
1、它的作用是导入完整的实用工具(utity)库,该库属于标准Java开发工具包的一部分。由于Vector位于java.util里,所以现在要么指定完整名称”(可省略import语句),要么简单地指定一个因为import是默认的)
2、若想导入单独一个类,可在import语句里指定那个类的名字:
import java.util.Vector
(现在,我们可以自由地使用vector,但是java.util 中的其他任何类仍是不可使用的。) - 在Java中:
1、 为Java创建一个源码文件的时候,它通常叫作一个“编辑单元”(有时也叫作“翻译单元”)。每个编译单元都必须有一个以 .java 结尾的名字。
2、而且在编译单元的内部,可以有一个公共(public)类,它必须拥有与文件相同的名字(包括大小写形式,但排除 .java 文件扩展名)。如果不这样做,编译器就会报告出错。
3、每个编译单元内都只能有一个public类(同样地,否则编译器会报告出错)。那个编译单元剩下的类(如果有的话)可在那个包外面的世界面前隐藏起来,因为它们并非“公共”的(非public)而且它们由用于主public类的“支撑”类组成。
4、编译一个Java文件时,我们会获得一个名字完全相同的输出文件。但对于Java文件中的每个类,它们都有 .Class 扩展名。因此,我们最终从少量的Java文件里有可能获得数量众多的 .class 文件。
之前学C的时候,已经习惯编译器先分割出一种过渡形式( .obj 文件),再用一个链接器将其与其他东西封装到一起(生成一个可执行文件 .exe 文件),或者与一个库封装到一起(生成一个库)。但那并不是Java的工作方式。一个有效的程序就是一系列 .class 文件,它们可以封装和压缩到一个JAR文件里(使用Java11提供的jar工具)Java解释器负责对这些文件的寻找、装载和解释。 - 若在一个文件的开头使用下述代码:package mypackage;
那么语句必须作为文件的第一个非注释语句出现,该语句的作用是指出这个编译单元属于名为mypackage的一个库的一部分。或者换句话说,它表明这个编译单元内的public类名位于mypackage这个名字的下面。如果其他人想使用这个名字,要么指出完整的名字,要么与联合使用 import 关键字(使用前面给出的选项)。注意根据Java包(封装)的约定,名字内的所有字母都应小写,甚至那些中间单词亦要如此。 - 作为一名库使用与设计者,一定要记住 pakage 和 import 关键字允许我们做的事情就是分割单个全局命名空间,保证我们不会遇到名字的冲突—无论有多少人使用因特网,也无论多少人用Java编写自己的类。根据约定,** package 名的第一部分是类创建的因特网域名,将公司的因特网域名以逆序的形式作为包名,并且对于不同的项目使用不同的子包。**,因为它一定是独一无二的
- 如果没有指定 public 或 private 这个部分(类、方法或变量)可以被同一个包中的所有方法访问。
2、多态
- 某一个事物,在不同时刻表现出来的不同状态
Cat c=new Cat();
Animal a=new Cat(); - 多态前提
1、要有继承关系。
2、要有方法重写。 其实没有也是可以的,但是如果没有这个就没有意义。
3、要有父类引用指向子类对象。
父 f = new 子(); - 多态中的成员访问的特点:
a:成员变量
编译看左边,运行看左边。
b:构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
c:成员方法
编译看左边,运行看右边。
d:静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的) - 多态的好处
a:提高了代码的维护性(继承保证)
b:提高了代码的扩展性(由多态保证)
——这里举一个非常典型的例子:
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show(); // 爱
B b = new C();
b.show(); // 你
}
}
【分析上面的程序,发现首先创建了一个B类的对象,但是是用A类的引用来接收,父类的引用指向子类的对象,这就是多态的形式。
因为使用这个引用去调用方法,因此这里应该遵循编译看左,执行看右。也就是编译器回首先查看A类里面有没有这个方法,然后再去执行B类里面的这个方法。显然,A里面存在这个方法,并且执行结果为打印一个“我”,但是最终结果并不是这个,B类里面没有重写A里面的show(),因此他直接继承了这show()方法,由于这个方法内部又调用了一个被重写过后的方法show2(),因此B类里面的show()方法执行结果为“爱”。
接下来又出现了多态,这次是使得B类的引用指向C类的对象,因为B本身继承于A,虽然B里面没有定义方法show(),但是他继承了A里面的方法,因此编译看左不会报错;执行看右边,发现C对B中的方法进行了重写,如果此时在C中show()方法前加@override标签发现不报错,C中的这个方法是调用B中的show(),B中的show()应该是:
public void show() {
show2();
}
这里的show2()当然指的是B中的方法,C调用了这个方法,但是由于show2()又被重写,因此C中执行的结果为在控制台输出“你”。这个例子非常典型,刚开始自己也没有想明白,现在再看,发现程序运用的就是多态的思想。】
- 通过多态的弊端——
引出问题:不能使用子类特有的功能
解决方法:把父类的引用强制转换为子类的引用(向下转型)
public class MyTest {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.num);//20
fu.show(); //zi show
Zi zi= (Zi) fu; //向下转型
System.out.println(zi.num);//200
zi.teyou();
}
}
class Fu{
int num=20;
public void show(){
System.out.println("父类的show");
}
}
class Zi extends Fu{
int num=200;
@Override
public void show() {
System.out.println("子类的show");
}
public void teyou(){
System.out.println("子类特有的方法");
}
}
执行结果为:
20
子类的show
200
子类特有的方法
3、抽象类
- 在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
- 抽象类特点:
1、抽象类和抽象方法必须用abstract关键字修饰
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();
2、抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
3、抽象类中可以有构造方法,抽象类不能进行实例化,那么要构造方法有什么作用呢?用于子类访问父类数据时的初始化
4、抽象类不能直接实例化那么,抽象类如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
5、抽象类的子类,要么是抽象类,要么重写抽象类中的所有抽象方法 - 抽象类的成员特点:
成员变量——既可以是变量,也可以是常量。
构造方法——有。用于子类访问父类数据的初始化。
成员方法——既可以是抽象的,也可以是非抽象的。
抽象方法——强制要求子类做的事情。
非抽象方法——子类继承的事情,提高代码复用性。
public static void main(String[] args) {
//抽象类,不能创建对象,只能通过子类创建对象间接地创建自己的对象
// Aniaml aniaml = new Aniaml();
Aniaml an = new Cat();
an.eat();
an.sleep();
an=new Dog();
an.eat();
an.sleep();
//为什么要引入抽象类的概念?
//我们将多个子类的共性功能向上抽取到父类当中,我们父类肯定知道这些子类的共性功能,但是父类没有必要知道,这些共性功能的具体实现是怎么样,因为也没有必要知道,因为每个子类都有差异性,如果我在父类中,给出了这个功能的具体实现,那么每个子类的这个功能,其实都是一样的,并不能体现出每个子类对这个功能的具体实现,所以父类,只需要给出这个功能的声明,而不需要给出功能的具体实现,具体实现,交由子类根据自身的差异去实现。
}
//抽象类
public abstract class Aniaml {
//抽象方法
public abstract void eat();
public abstract void sleep() ;
}
public class Cat extends Aniaml{
public void catchMouse(){
System.out.println("抓老鼠");
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫喜欢白天睡觉");
}
}
public class Dog extends Aniaml{
public void lookDoor(){
System.out.println("看门");
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗躺着睡觉");
}
}
- abstract不能和哪些关键字共存?
private 冲突
【abstract本身就是抽象的意思,它需要子类来实现它里面的方法,如果你将父类里面的方法设为私有的,子类都不能继承,何谈去实现父类的方法】
final 冲突
【final关键字修饰的方法本身就不能被重写,如果父类里面的抽象方法是final的,子类就没有办法进行重写;如果父类本身就是final修饰,子类都没办法继承,也就没有办法去重写】
static 不能共存 ,无意义
【父类如果有staitic修饰的方法,意味着这个方法是随着类的产生而产生,可以直接使用类名来调用,也就是说静态方法并不会依赖于继承关系,所以这两个关键字共存没有意义】
4、接口
- 为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现。比如马戏团里的猫类与狗类可能会有区别于普通猫狗的本领,将来那些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可
- 接口特点
1、接口用关键字interface表示
格式: interface 接口名 {}
2、类实现接口用implements表示
格式: class 类名 implements 接口名 {}
3、接口不能实例化
那么,接口如何实例化呢 ? 按照多态的方式来实例化。
4、接口的子类
可以是抽象类。但是意义不大。
可以是具体类。要重写接口中的所有抽象方法。 - 接口成员特点
成员变量;只能是常量,并且是静态的。——默认修饰符:public static final
(建议:自己手动给出)
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。——默认修饰符:public abstract
(建议:自己手动给出)
public class MyTest {
public static void main(String[] args) {
//接口:定义事务的额外的扩展的功能,接口也会定义规范和规则
//interface
//接口不能创建对象
//MyInterface 就是 Cat 的父接口 父接口与子类的关系 叫做实现关系implements
MyInterface my = new Cat(); //多态
my.jump();
Cat cat= (Cat) my;
cat.eat();
cat.catchMouse();
}
}
public class Cat implements MyInterface{
public void eat(){
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
@Override
public void jump() {
System.out.println("经过不断的练习,猫学会了跳高");
}
}
public class Dog implements MyInterface{
@Override
public void jump() {
System.out.println("狗经过了练习,学会了跳高");
}
}
//interface 定义接口
//接口中的方法是抽象的,不给出功能的具体实现
public interface MyInterface {
//提供跳高的功能
public abstract void jump();
}
程序输出:
经过不断的练习,猫学会了跳高
猫吃鱼
猫抓老鼠
5、类、抽象类、接口
- 类与类:
继承关系,只能单继承,可以多层继承。 - 类与接口:
实现关系,可以单实现,也可以多实现。 - 接口与接口:
继承关系,可以单继承,也可以多继承。 - 抽象类与接口的区别:
1、成员区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量
成员方法:只可以抽象
2、关系区别
类与类:继承,单继承
类与接口:实现,单实现,多实现
接口与接口:继承,单继承,多继承
3、设计理念区别
抽象类——被继承体现的是:”is a”的关系。 抽象类中定义的是该继承体系的共性功能。
接口——被实现体现的是:”like a”的关系。 接口中定义的是该继承体系的扩展功能。
public class MyTest {
public static void main(String[] args) {
/*
动物类:姓名,年龄,吃饭,睡觉。
动物培训接口:跳高
猫继承动物类
狗继承动物类
部分猫继承猫类并实现跳高接口
部分狗继承狗类并实现跳高接口*/
Animal an = new 旺财();
an.name="旺财";
an.age=2;
System.out.println(an.name);
System.out.println(an.age);
an.sleep();
an.eat();
旺财 wc= (旺财) an;
wc.lookDoor();
高菲狗 gf = new 高菲狗();
an=gf;
an.name="高菲";
an.age=3;
System.out.println(an.name);
System.out.println(an.age);
an.eat();
an.sleep();
JumpInterface jumpInterface= gf;
jumpInterface.jump();
System.out.println("----------------");
Animal an1 = new 加菲猫();
an1.name="加菲猫";
an1.age=4;
System.out.println(an1.name);
System.out.println(an1.age);
an1.sleep();
an1.eat();
加菲猫 jf= (加菲猫) an1;
jf.catchMouse();
狸花猫 lh = new 狸花猫();
an1=lh;
an1.name="狸花猫";
an1.age=6;
System.out.println(an1.name);
System.out.println(an1.age);
an1.eat();
an1.sleep();
JumpInterface jumpInterface1= jf;
jumpInterface1.jump();
}
}
public interface JumpInterface {
void jump();
}
public abstract class Animal {
String name;
int age;
public abstract void eat();
public abstract void sleep();
}
public class Cat extends Animal{
public void catchMouse(){
System.out.println("抓老鼠");
}
@Override
public void eat() {
System.out.println("猫爱吃鱼");
}
@Override
public void sleep() {
System.out.println("猫白天睡觉");
}
}
public class Dog extends Animal{
public void lookDoor(){
System.out.println("狗看门");
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗躺着睡觉");
}
}
public class 加菲猫 extends Cat implements JumpInterface{
@Override
public void eat() {
System.out.println("加菲猫吃小鱼干");
}
@Override
public void jump() {
System.out.println("加菲猫经过不断的学习,学会了跳高");
}
}
public class 旺财 extends Dog{
@Override
public void eat() {
System.out.println("旺财吃狗粮");
}
}
public class 狸花猫 extends Cat{
@Override
public void eat() {
System.out.println("狸花猫吃老鼠");
}
}
public class 高菲狗 extends Dog implements JumpInterface{
@Override
public void eat() {
System.out.println("高菲吃狗罐头");
}
@Override
public void jump() {
System.out.println("高菲学会了跳高");
}
}
输出结果为:
旺财
2
狗躺着睡觉
旺财吃狗粮
狗看门
高菲
3
高菲吃狗罐头
狗躺着睡觉
高菲学会了跳高
----------------
加菲猫
4
猫白天睡觉
加菲猫吃小鱼干
抓老鼠
狸花猫
6
狸花猫吃老鼠
猫白天睡觉
加菲猫经过不断的学习,学会了跳高
6、方法参数类型以及返回值类型问题
1、形参为类类型:
public class MyTest2 {
public static void main(String[] args) {
//一个方法的形参一个类类型,就传递该类的对象
Student student = new Student();
test(student,20);
System.out.println(student.age);
student.show(new Student(),21);
System.out.println((new Student()).age);
}
public static void test(Student student, int a){
student.age=a;
}
}
class Student{
int age=24;
public void show(Student student,int a){
student.age=a;
}
}
输出结果为:
20
24
2、形参为抽象类类型
public class MyTest {
public static void main(String[] args) {
//方法的形参要一个抽象类类型,就传递该抽象类的子类对象
Son son = new Son();
test(son,15);
}
public static void test(Teacher teacher,int num){
//这里实质上是多态的形式,使得父类的引用接收子类的对象
teacher.num=num;//成员变量执行编译都看父类
teacher.show(num);//成员方法编译看父类,执行看子类
}
}
abstract class Teacher{
int num=100;
public abstract void show(int num);
}
class Son extends Teacher{
int num = 2;
@Override
public void show(int num) {
System.out.println(this.num);//2
System.out.println(num);//15
System.out.println(super.num);//15
}
}
//因为程序在执行test()方法时,就已经将父类中的成员变量进行了重新赋值,因此输出的super().num是赋值后的值
3、形参为接口类型
public class MyTest {
public static void main(String[] args) {
//方法的形参需要一个接口类型,传一个实现该接口的子类对象
MyClass myClass = new MyClass();
test(myClass,60);
System.out.println(Myinterface.num);
}
public static void test(Myinterface myinterface,int num){
myinterface.show(num);
}
}
interface Myinterface{
//接口中只有静态自定义常量
public static final int num=200;
public abstract void show(int num);
}
class MyClass implements Myinterface{
int num=10;
@Override
public void show(int num) {
System.out.println(this.num);
}
}
输出结果为:
10
200
4、方法的返回值为类类型
public class MyTest {
public static void main(String[] args) {
Student student = new Student();
Student student1 = test(student, 1);
System.out.println(student.num);
System.out.println(student1.num);
System.out.println("----------------------------------");
student.show(student,2);
student1.show(student,3);
System.out.println(student.num);
System.out.println(student1.num);
}
public static Student test(Student student,int num){
student.num=num;
//一个方法的返回值类型,要一个类类型,就返回该类的一个对象
return new Student();
}
}
class Student{
int num=4;
public void show(Student student,int num){
this.num=num;
}
}
输出结果为:
1
4
----------------------------------
2
3
5、方法的返回值为抽象类类型
public class MyTest {
public static void main(String[] args) {
MyClass myClass = test(new Zi(), 1);
myClass.show(2);
}
public static MyClass test(MyClass myClass,int num){
myClass.num=num;
//当一个方法的返回值类型为抽象类类型,就返回一个该抽象类的子类对象
return new Zi();
}
}
abstract class MyClass{
int num=3;
public abstract void show(int num);
}
class Zi extends MyClass{
@Override
public void show(int num) {
System.out.println(this.num);
System.out.println(super.num);
}
}
输出结果为:
3
3
6、方法的返回值为接口类型
public class MyTest3 {
public static void main(String[] args) {
MyInterface test = test(1);
test.show(2);
}
//一个方法的返回值类型要一个接口类型,就返回一个实现该接口的子类对象
public static MyInterface test(int num){
System.out.println(num);
return new MyDemo();
}
}
interface MyInterface{
void show(int num);
}
class MyDemo implements MyInterface{
@Override
public void show(int num) {
System.out.println(num);
}
}
输出结果为:
1
2
7、链式编程
public class MyTest {
public static void main(String[] args) {
Student student = new Student();
Student student1 = student.getStudent(student, 1);
Student student2=student1.show();
System.out.println(student2.num);
System.out.println("---------------------------");
//以上的代码可以用链式编程来调用
//链式编程:当你调用完一个方法后,这个方法的返回值是一个对象。那么你就可以紧接着打点。在去调用这个对象的方法
int a= new Student().getStudent(new Student(), 2).show().num;
System.out.println(a);
}
}
class Student{
int num=3;
public Student getStudent(Student student,int num){
student.num=num;
return new Student();
}
public Student show(){
// System.out.println(num);
return this;
}
}
输出结果为:
3
---------------------------
3
7、权限修饰符
针对类内的每个成员的每个定义,Java访问指示符public、protected、private都置于它们的最前面——无论他们是一个数据成员还是一个方法,每个访问指示符都只控制着对那个特定定义的访问
1、“友好的”
如果跟本不指定任何访问指示符,默认的访没有关键字,但他通常称为“友好”访问,这意味着当前包内的所有类都能“友好的”访问该成员,但对包外的类,它是私有的;因此我们说友好元素拥有“包访问”权限
2、public:接口访问
使用public关键字时,它意味着紧随在public之后的成员声明适用于外界所有类,特别是适用于使用库的库成员。
3、private:不能接触!
该关键字意味着除非那个特定的类,而且从那个类的方法里,否则没有人能访问那个成员,同一个包内不同类内也不行。使用该关键字还是很有用处的,我们应该根据自己的需求去设计程序
4、protected:“有好的一种”
与继承的概念相联系,只有子类继承于父类才可以访问父类里面的protected成员,若新建一个包,并从另一个包内的某个类里面继承,则能访问的就是原来包内的public成员与protected成员
8、内部类
- 将一个类的定义置于另一个类中,这就叫做“内部类”,可以利用内部类对那些逻辑上相互联系的类进行分组,并可以控制一个类在另一个类中的可见性
- 根据内部类的定义位置不同,可将它分为:
——成员内部类和局部内部类 - 内部类访问特点
1、内部类可以直接访问外部类的成员,包括私有。
2、外部类要访问内部类的成员,必须创建对象。 - 如何在测试类中直接访问内部类的成员?
格式: 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
//成员内部类
public class MyTest {
class Contents{
private int i=1;
public int value(){
return i;
}
}
class Destination{
private String label;
Destination(String whereTo){
label=whereTo;
}
String redLabel(){
return label;
}
}
public void ship(String dest){
Contents c=new Contents();
Destination d=new Destination(dest);
}
public static void main(String[] args) {
MyTest p=new MyTest();
p.ship("Tanzania");
}
}
//一个外部类拥有特殊的方法,他会返回一个内部类的引用
public class MyTest {
class Contents{
private int i=1;
public int value(){
return i;
}
}
class Destination{
private String label;
Destination(String whereTo){
label=whereTo;
}
String redLabel(){
return label;
}
}
public Destination to(String s){
return new Destination(s);
}
public Contents cont(){
return new Contents();
}
public void ship(String dest){
Contents c=new Contents();
Destination d=new Destination(dest);
}
public static void main(String[] args) {
MyTest p=new MyTest();
p.ship("Tanzania");
MyTest q=new MyTest();
MyTest.Contents c=q.cont();
MyTest.Destination d=q.to("Borneo");
}
}
//局部内部类
public class MyTest {
public static void main(String[] args) {
//局部内部类:把内部类定义到了外部类的局部位置(方法中)
//内部类可以直接范围外部类的成员包括私有的。
//局部内部类,外界无法直接创建其对象
new Outer().waiShow();
}
}
class Outer {
int num = 12;
private double aa = 3.14;
public void haha() {
System.out.println("哈哈");
}
public void waiShow() {
//定义局部内部类
class Inner {
int c = 2;
public void neiHaha() {
System.out.println("这是局部内部类的方法");
}
public void neiTest() {
System.out.println(num);
System.out.println(aa);
waiSiyou();
}
}
//创建内部类对象
Inner inner = new Inner();
inner.neiHaha();
}
private void waiSiyou() {
System.out.println("这是外部类私有的方法");
}
}
输出结果为:
这是局部内部类的方法
可以发现使用内部类是从两方面考虑:
1、正如上面展示的,我们希望以实行某种形式接口,使它能创建和返回一个句柄
2、要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序设计,同时不愿意把它公开
9、匿名内部类
- 联系之前的匿名对象,可以得知匿名内部类是一个没有名字的内部类,匿名内部类的本质是一个对象,是实现该接口或继承了该抽象类的子类对象,前提是有一个接口或者抽象类
//接口:
public class MyTest2 {
public static void main(String[] args) {
new MyInterface(){
@Override
public void show() {
System.out.println("show");
}
}.show();
}
}
interface MyInterface{
void show();
}
输出结果为;
show
抽象类:
public class MyTest {
public static void main(String[] args) {
new Fu(){
@Override
public void hehe() {
System.out.println("呵呵1");
}
@Override
public void haha() {
System.out.println("哈哈1");
}
}.haha();
new Fu() {
@Override
public void hehe() {
System.out.println("呵呵2");
}
@Override
public void haha() {
System.out.println("哈哈2");
}
}.hehe();
}
}
abstract class Fu{
public abstract void hehe();
public abstract void haha();
}
执行结果为:
哈哈1
呵呵2
- 匿名类中的this关键字:
interface Inter {
public static final int a = 5 ;
public abstract void show();
}
public class MyTest {
public static void main(String[] args) {
new Inter() {
public void show() {
//this 代表匿名内部类
System.out.println(this.a);//23
}
}.show();
}
}
输出结果为:
5
- 这里加一道当时没有做出来的题目
// 要求在控制台输出”HelloWorld”
interface Inter {
void show();
}
class Outer {
public static Inter method(){
return new Inter(){
@Override
public void show() {
System.out.println("Hello World!");
}
};
}
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
总结:这部分面对对象的知识概念较多,而且有时候容易搞混,目前发现自己只能理解这些概念并举一些很简单的例子,还没能达到自己设计程序的同时将这些思想运用进去,但是熟能生巧,我希望自己以后在多敲代码的同时能够用心体会这部分内容。