面向对象的个人理解(从C/C++到Java)

  • Post author:
  • Post category:java



目录


前言


功能分类


干扰的起源


调整1


调整2


比较:


总结


用类(class)消除干扰


Dog类


Cat类


入口类


总结


JDK中的一些实现


尝试


代码重用


类型化(Type)


继承


总结


访问控制


私有(private)与公开(public)


保护(protected)


局部实现


内部类


匿名类


局部类


总结


一些细节


静态成员


静态类


Lamda


总结


前言

功能分类

类(class)的第一个功能是隔离,起到边界的作用,使得不同功能的代码互不干扰。

干扰的起源

在非面向对象的语言中,我们主要定义结构和函数来实现功能。下边用C语言来举个例子。

某程序员写了宠物模拟器,不过开始他只有一只狗,于是他写了一个只有狗子特性的代码,代码功能就是模拟模拟狗子被撸后,会㕵㕵叫:

注:C语言代码使用Visual Studio编写。

#include<stdio.h>
#include<locale.h>

const wchar_t* name = L"旺才";

void call() {
	wprintf(L"%s,过来!\n",name);
}

void pat() {
	wprintf(L"汪汪\n");
}

void main() {
	setlocale(LC_ALL, "");
	wprintf(L"撸狗\n-----------\n");
	call();
	pat();
}

运行结果:

此时这个程序没啥问题,接着又养了一只猫,猫跟狗差不多的功能,但我们不能重复定义call()和pat()函数,这样会有冲突,那需要对代码做些改动,可以接受两只宠物。

这里至少有两种思路,一种是再复制狗的代码,改下名称;另一种,保持函数名称不变,添加参数进行区别。

调整1

对于前者,可能改成这样:

#include<stdio.h>
#include<locale.h>

const wchar_t* dog_name = L"旺才";
const wchar_t* cat_name = L"花花";

void dog_call() {
	wprintf(L"%s,过来!\n", dog_name);
}

void cat_call() {
	wprintf(L"%s,过来!\n", cat_name);
}

void dog_pat() {
	wprintf(L"汪汪\n");
}

void cat_pat() {
	wprintf(L"喵喵\n");
}
void main() {
	setlocale(LC_ALL, "");
	char c = '0';

	while (c != 'q') {
		if (c != '\n')
			wprintf(L">>\n请选择宠物:狗(d),猫(c)\n");
		c = getchar();
		if (c == '\n') continue;
		if (c == 'd') {
			wprintf(L"撸狗\n-----------\n");
			dog_call();
			dog_pat();
		}
		else if (c == 'c') {
			wprintf(L"撸猫\n-----------\n");
			cat_call();
			cat_pat();
		}
		else if (c != 'q') {
			wprintf(L"所先宠物不存在\n");
		}
	}
}

运行结果:

调整2

另一种改成这样:

#include<stdio.h>
#include<locale.h>

const wchar_t* dog_name = L"旺才";
const wchar_t* cat_name = L"花花";

void call(char pet) {
	if (pet == 'd')
		wprintf(L"%s,过来!\n", dog_name);
	else if (pet == 'c')
		wprintf(L"%s,过来!\n", cat_name);
	else
		wprintf(L"所选宠物不存在\n");
}

void pat(char pet) {
	if (pet == 'd')
		wprintf(L"汪汪\n");
	else if (pet == 'c')
		wprintf(L"喵喵\n");
}

void main() {
	setlocale(LC_ALL, "");
	char c = '0';

	while (c != 'q') {
		if (c != '\n')
			wprintf(L">>\n请选择宠物:狗(d),猫(c)\n");
		c = getchar();
		if (c == '\n') continue;
		if (c == 'd') {
			wprintf(L"撸狗\n-----------\n");
		}
		else if (c == 'c') {
			wprintf(L"撸猫\n-----------\n");
		}
		call(c);
		pat(c);

	}
}

运行结果:

比较:

前者命名冲突,代码重复。好处是比较直观,小白都能看懂。

后者代码整洁,但交叉比较,耦合性高,牵一发可能动全身。

总结

不管用哪一种代码改动,多多少少都会对别的部分形成干扰,虽然有方法尽量去避免这些干扰,但往往对程序员的要求太高,反而降低了开发效率。产生干扰的主要原因是,C语言只能做到函数级别的代码分组,增加功能就要不断地增加函数,当函数的数据到达一定级别时,名称的冲突必然导致系统的不可维护。我们可以想像一下,当这个程序有了几百上千种宠物后,代码会是什么样子的?

用类(class)消除干扰

类实现了更大范围的代码分组,将相关的函数变成成员方法,将全局变量变成成员字段放在一个类中,与其它代码隔离开来,在小范围内可以有效地避开命名冲突的问题。就好比,行政区中全国乡镇的名称重复的很多,但在同一个区县中就不存在了。为了区分同名的乡镇,我们只要区分区县就可以了。所以前边的代码,用java的方式,我们就可以写成两个类,一个Dog类,一个Cat类,虽然他们有相同的部分,但互不干扰。

Dog类

/**
 * 狗狗
 *
 */
public class Dog {
	private static String name = "旺财";

	public static void call() {
		System.out.format("%s\n", name);
	}

	public static void pat() {
		System.out.println("汪汪!");
	}

}

Cat类

/**
 * 猫猫
 *
 */
public class Cat {

	private static String name = "花花";

	public static void call() {
		System.out.format("%s\n", name);
	}

	/**
	 * 猫会妙妙
	 */
	public static void pat() {
		System.out.println("喵喵");
	}
}

入口类

import java.io.IOException;

public class App {

	public static void main(String[] args) throws IOException {

		char c = '0';

		while (c != 'q') {
			if (c != '\n' && c != '\r')
				System.out.println(">>\n请选择宠物:狗(d),猫(c)\n");

			c = (char) System.in.read();
			if (c == '\n' || c == '\r')
				continue;
			if (c == 'd') {
				System.out.println("撸狗\n-----------\n");
				Dog.call();
				Dog.pat();
			} else if (c == 'c') {
				System.out.println("撸猫\n-----------\n");
				Cat.call();
				Cat.pat();
			} else if (c != 'q') {
				System.out.println("所先宠物不存在\n");
			}

		}
	}

}

运行结果:

总结

JDK中的一些实现




Math (Java SE 17 & JDK 17)


declaration: module: java.base, package: java.lang, class: Math



https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Math.html






System (Java SE 17 & JDK 17)


declaration: module: java.base, package: java.lang, class: System



https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.html





Executors (Java SE 17 & JDK 17)


declaration: module: java.base, package: java.util.concurrent, class: Executors



https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/Executors.html


尝试

用Java重构之后,加宠物就方便很多了,只要类不重名,其它代码随便写。比如增加一个Parrot类:

/**
 * 鹦鹉
 *
 */
public class Parrot {

	private static String name = "鹦哥";

	public static void call() {
		System.out.format("%s\n", name);
	}

	public static void pat() {
		System.out.println("烦死了!");
	}

}

修改App.java

import java.io.IOException;

public class App {

	public static void main(String[] args) throws IOException {

		char c = '0';

		while (c != 'q') {
			if (c != '\n' && c != '\r')
				System.out.println(">>\n请选择宠物:狗(d),猫(c),鹦鹉(p)\n");

			c = (char) System.in.read();
			if (c == '\n' || c == '\r')
				continue;
			if (c == 'd') {
				System.out.println("撸狗\n-----------\n");
				Dog.call();
				Dog.pat();
			} else if (c == 'c') {
				System.out.println("撸猫\n-----------\n");
				Cat.call();
				Cat.pat();
			} else if (c == 'p') {
				System.out.println("撸鹦鹉\n-----------\n");
				Parrot.call();
				Parrot.pat();
			} else if (c != 'q') {
				System.out.println("所先宠物不存在\n");
			}

		}
	}

}

运行结果:

代码重用

前边,虽然解决了代码中的某些命名冲突的问题,但有个最大的缺点,就是重复率太高,如果不看具体实现,字段、方法的名称几乎是一样的。其实这些内容是可以做到重用的,Java的代码重用除了传统的定义数据结构和通用函数外,还可以类型化(Type)及继承。

类型化(Type)

前边的示例中,一个类只实现了一个宠物的行为,如果又增加了一只狗狗,是不是要增加一个类,比如Dog1,其实大可不必。前边之所以只能表述一个宠物,是因为类的成员都标成了static,意思就是这个类中的代码跟面向过程没啥差别,只是调用前需要加上类名作为前辍。增加的狗狗目前来说,可能只是名字不一样,所以只要一个狗狗类的模板即可。

Java的类除了分组的作用,本身也是可以作为一个数据类型来使用的,此时只要将类成员的static关键去掉即可。接下来改下Dog类、Cat类和Parrot类。

Dog类

/**
 * 狗狗
 *
 */
public class Dog {
	private String name = "旺财";

	public void call() {
		System.out.format("%s\n", name);
	}

	public void pat() {
		System.out.println("汪汪!");
	}

}

Cat类

/**
 * 猫猫
 *
 */
public class Cat {

	private String name = "花花";

	public void call() {
		System.out.format("%s\n", name);
	}

	/**
	 * 猫会妙妙
	 */
	public void pat() {
		System.out.println("喵喵");
	}
}

/**
 * 鹦鹉
 *
 */
public class Parrot {

	private String name = "鹦哥";

	public void call() {
		System.out.format("%s\n", name);
	}

	public void pat() {
		System.out.println("烦死了!");
	}

}

此时,各个类就成类型(Type)结构了,如果调用这些代码,就得先创建类型实例,更改App类的代码,变成这样:

import java.io.IOException;

public class App {

	public static void main(String[] args) throws IOException {

		char c = '0';

		while (c != 'q') {
			if (c != '\n' && c != '\r')
				System.out.println(">>\n请选择宠物:狗(d),猫(c),鹦鹉(p)\n");

			c = (char) System.in.read();
			if (c == '\n' || c == '\r')
				continue;
			if (c == 'd') {
				System.out.println("撸狗\n-----------\n");
				Dog dog = new Dog();
				dog.call();
				dog.pat();
			} else if (c == 'c') {
				System.out.println("撸猫\n-----------\n");
				Cat cat = new Cat();
				cat.call();
				cat.pat();
			} else if (c == 'p') {
				System.out.println("撸鹦鹉\n-----------\n");
				Parrot parrot = new Parrot();
				parrot.call();
				parrot.pat();
			} else if (c != 'q') {
				System.out.println("所先宠物不存在\n");
			}
		}
	}

}

虽然多了点代码,但我们可以复用这个结构,只要做少量的修改,就可以创建无数个宠物。改一下Dog类,增加两个构造器,一个是默认的无参数,另一个是带参数的,这样可以创建对象的修改狗狗的名字:

/**
 * 狗狗
 *
 */
public class Dog {
	private String name = "旺财";

	public Dog() {
		
	}
	
	public Dog(String dogName) {
		name = dogName;
	}

	public void call() {
		System.out.format("%s\n", name);
	}

	public void pat() {
		System.out.println("汪汪!");
	}

}

App类

import java.io.IOException;

public class App {

	public static void main(String[] args) throws IOException {

		char c = '0';

		while (c != 'q') {
			if (c != '\n' && c != '\r')
				System.out.println(">>\n请选择宠物:狗(d),猫(c),鹦鹉(p)\n");

			c = (char) System.in.read();
			if (c == '\n' || c == '\r')
				continue;
			if (c == 'd') {
				System.out.println("撸两条狗\n-----------\n");
				Dog dog = new Dog();
				dog.call();
				dog.pat();
				
				Dog dog1 = new Dog("小贝");
				dog1.call();
				dog1.pat();
			} else if (c == 'c') {
				System.out.println("撸猫\n-----------\n");
				Cat cat = new Cat();
				cat.call();
				cat.pat();
			} else if (c == 'p') {
				System.out.println("撸鹦鹉\n-----------\n");
				Parrot parrot = new Parrot();
				parrot.call();
				parrot.pat();
			} else if (c != 'q') {
				System.out.println("所先宠物不存在\n");
			}
		}
	}

}

运行效果:

继承

另一种代码重用的方式就是继承了,上述示例中无论狗狗、猫咪还是鹦鹉,它们行为方式是一样的,都是撸完后做出打出一行文本,无非就是内容上的差别,我们可以相同的部分提取出,单独创建一类在存放,响应内容的由具体的宠物类中实现,我们创建一个Pet类:

/**
 * 小可爱们
 *
 */
public class Pet {
	private String name = "无名";// 宠物都有名字

	public Pet() {

	}

	public Pet(String petName) {
		name = petName;
	}

	public void call() {
		System.out.format("%s\n", name);
	}

	public void pat() {
		System.out.println(response());
	}

	/**
	 * 默认没反应,由具体对象实现
	 * @return
	 */
	protected String response() {
		return "";
	}
}

然后修改各个宠物类:

/**
 * 狗狗
 *
 */
public class Dog extends Pet {
	public Dog() {
		super();
	}

	public Dog(String dogName) {
		super(dogName);
	}

	@Override
	protected String response() {
		return "汪汪!";
	}

}
/**
 * 猫猫
 *
 */
public class Cat extends Pet {

	public Cat() {
		this("花花");
	}

	public Cat(String catName) {
		super(catName);
	}

	@Override
	protected String response() {
		return "喵喵!";
	}

}

/**
 * 鹦鹉
 *
 */
public class Parrot extends Pet {

	public Parrot() {
		this("鹦哥");
	}

	public Parrot(String parrotName) {
		super(parrotName);
	}

	@Override
	protected String response() {
		return "烦死了!";
	}

}

运行结果:

总结

为了实现代码的重用,实际还是有点代价的,代码的结构及语法都复杂了不少,但有了IDE的支撑,以后往后代码的增多,这点代价还是非常值的。接下来可以尝试增加两个宠物,一个是黄金莽,另一个是猫的细分种类咖啡猫。

对于黄金莽,即不需要名字,也不会发声,代码可以写成这样,基本上不用写什么代码:

/**
 * 黄金莽
 *
 */
public class GoldBoa extends Pet {
	public GoldBoa() {
		super("");
	}

}

对于 咖啡猫,除了跟普通猫一样,还会说人话:

/**
 * 咖啡猫
 *
 */
public class Garfield extends Cat {
	public Garfield() {
		super("");
	}

	public Garfield(String name) {
		super(name);
	}

	public void speak() {
		System.out.print("我会说话!");
	}
}

修改一下App,创建新的宠物:

import java.io.IOException;

public class App {

	public static void main(String[] args) throws IOException {

		char c = '0';

		while (c != 'q') {
			if (c != '\n' && c != '\r')
				System.out.println(">>\n请选择宠物:狗(d),猫(c),鹦鹉(p),黄金莽(b)\n");

			c = (char) System.in.read();
			if (c == '\n' || c == '\r')
				continue;
			if (c == 'd') {
				System.out.println("撸两条狗\n-----------\n");
				Dog dog = new Dog();
				dog.call();
				dog.pat();

				Dog dog1 = new Dog("小贝");
				dog1.call();
				dog1.pat();
			} else if (c == 'c') {
				System.out.println("撸猫\n-----------\n");
				Cat cat = new Cat();
				cat.call();
				cat.pat();

				Garfield garfield = new Garfield();
				garfield.call();
				garfield.pat();
				garfield.speak();

			} else if (c == 'p') {
				System.out.println("撸鹦鹉\n-----------\n");
				Parrot parrot = new Parrot();
				parrot.call();
				parrot.pat();
			} else if (c == 'b') {
				System.out.println("撸黄金莽\n-----------\n");
				GoldBoa boa = new GoldBoa();
				boa.call();
				boa.pat();
			} else if (c != 'q') {
				System.out.println("所先宠物不存在\n");
			}
		}
	}

}

运行结果:

访问控制

代码进行分组后,还可以对内部成员进行访问控制。这样可以对代码进行更多的约束控制,上述示例中,每个宠物都有自己的名字,名字一旦起好,别人就不能随意发动了,所以在定义类的时候,name这个字段前边加上了private这个修饰符,说明不能被外部更改,因为加了这个修饰后,程序运行起来后,这个代码对外部的代码是不可见的。就好比路上见到一个人,你不知道这个有没有带钱包,因为钱包是私有的,一般是不让外人看到的。

私有(

private

)与公开(

public

)

宠物的名字虽然不可修改,但我们还是可以得到宠物的名字的,然后修改一下Pet类,增加一个获取名字的方法,这个方法是公开的,也就说谁都可以知道宠物的名字,所以前边加了一个修改符public:

/**
 * 小可爱们
 *
 */
public class Pet {
	private String name = "无名";// 宠物都有名字

	public Pet() {

	}

	public Pet(String petName) {
		name = petName;
	}

	public String getName() {
		return name;
	}

	public void call() {
		System.out.format("%s\n", name);
	}

	public void pat() {
		System.out.println(response());
	}

	/**
	 * 默认没反应,由具体对象实现
	 * 
	 * @return
	 */
	protected String response() {
		return "";
	}
}

再改下App类:

import java.io.IOException;

public class App {

	public static void main(String[] args) throws IOException {

		char c = '0';

		while (c != 'q') {
			if (c != '\n' && c != '\r')
				System.out.println(">>\n请选择宠物:狗(d),猫(c),鹦鹉(p),黄金莽(b)\n");

			c = (char) System.in.read();
			if (c == '\n' || c == '\r')
				continue;
			if (c == 'd') {
				System.out.println("撸两条狗\n-----------\n");
				Dog dog = new Dog();
				System.out.format("宠物名字:%s\n",dog.getName());
				dog.call();
				dog.pat();

				Dog dog1 = new Dog("小贝");
				System.out.format("宠物名字:%s\n",dog1.getName());
				dog1.call();
				dog1.pat();
			} else if (c == 'c') {
				System.out.println("撸猫\n-----------\n");
				Cat cat = new Cat();
				System.out.format("宠物名字:%s\n",cat.getName());
				cat.call();
				cat.pat();

				Garfield garfield = new Garfield();
				System.out.format("宠物名字:%s\n",garfield.getName());
				garfield.call();
				garfield.pat();
				garfield.speak();

			} else if (c == 'p') {
				System.out.println("撸鹦鹉\n-----------\n");
				Parrot parrot = new Parrot();
				System.out.format("宠物名字:%s\n",parrot.getName());
				parrot.call();
				parrot.pat();
			} else if (c == 'b') {
				System.out.println("撸黄金莽\n-----------\n");
				GoldBoa boa = new GoldBoa();
				System.out.format("宠物名字:%s\n",boa.getName());
				boa.call();
				boa.pat();
			} else if (c != 'q') {
				System.out.println("所先宠物不存在\n");
			}
		}
	}

}

运行效果:

保护(protected)

protected这个关键字是继承时专用的。表示可以提供给子类访问,这样的话就可以将一些方法让子类调用、重写或实现。之前代码中已经在Pet类中定义了一个叫做response()的方法,这个方法在App中是不可见的,但Dog、Cat等类中是可以访问的。具体请查看之前的代码,这里不复述。

局部实现

内部类

之前,我们撸宠物的时候,宠物是直接做出反应的,但有时候可能是反应迟钝的,这时可以用线程来模拟一下,线程需要写一个类实现Runnable接口,但这种反应是每个动物特有的,所以不必定义全局类,只定义一个内部类来实现,以狗子举例:

/**
 * 狗狗
 *
 */
public class Dog extends Pet {
	public Dog() {
		this("汪财");
	}

	public Dog(String dogName) {
		super(dogName);
	}

	@Override
	protected String response() {
		return "汪汪!";
	}

	@Override
	public void pat() {
		Thread daze = new Thread(new DogResponse());
		daze.start();
	}

	class DogResponse implements Runnable {

		@Override
		public void run() {
			try {
				System.out.println("先发个呆!");				
				Thread.sleep(3000);
				System.out.println(response());	
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

	}

}

为了方便起见,再改下App, 去掉一只狗狗:

import java.io.IOException;

public class App {

	public static void main(String[] args) throws IOException {

		char c = '0';

		while (c != 'q') {
			if (c != '\n' && c != '\r')
				System.out.println(">>\n请选择宠物:狗(d),猫(c),鹦鹉(p),黄金莽(b)\n");

			c = (char) System.in.read();
			if (c == '\n' || c == '\r')
				continue;
			if (c == 'd') {
				System.out.println("撸两条狗\n-----------\n");
				Dog dog = new Dog();
				System.out.format("宠物名字:%s\n",dog.getName());
				dog.call();
				dog.pat();

			} else if (c == 'c') {
				System.out.println("撸猫\n-----------\n");
				Cat cat = new Cat();
				System.out.format("宠物名字:%s\n",cat.getName());
				cat.call();
				cat.pat();

				Garfield garfield = new Garfield();
				System.out.format("宠物名字:%s\n",garfield.getName());
				garfield.call();
				garfield.pat();
				garfield.speak();

			} else if (c == 'p') {
				System.out.println("撸鹦鹉\n-----------\n");
				Parrot parrot = new Parrot();
				System.out.format("宠物名字:%s\n",parrot.getName());
				parrot.call();
				parrot.pat();
			} else if (c == 'b') {
				System.out.println("撸黄金莽\n-----------\n");
				GoldBoa boa = new GoldBoa();
				System.out.format("宠物名字:%s\n",boa.getName());
				boa.call();
				boa.pat();
			} else if (c != 'q') {
				System.out.println("所先宠物不存在\n");
			}
		}
	}

}

运行效果:

匿名类

如果嫌定义内部类麻烦的话,也可以使用匿名类,使代码更紧凑一点,狗狗的代码变成了这样:

/**
 * 狗狗
 *
 */
public class Dog extends Pet {
	public Dog() {
		this("汪财");
	}

	public Dog(String dogName) {
		super(dogName);
	}

	@Override
	protected String response() {
		return "汪汪!";
	}

	@Override
	public void pat() {
		Thread daze = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					System.out.println("先发个呆!");
					Thread.sleep(3000);
					System.out.println("3秒后......");
					System.out.println(response());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		});
		daze.start();
	}

}

运行效果同上。

局部类

宠物养了就是玩的,有时候会让宠物表演,当然不是真的表演,而随机做一些动物,我们可以定义一个类来存放宠物表演时的状态,但表演也是经常性的,而且仅仅是表演时用到,所以不必定义一个全局类来表示这些动作,也不用定义内部类,别的地方用不到,因而可以直接在方法内定义一个局部类,以狗狗为例:

/**
 * 狗狗
 *
 */
public class Dog extends Pet {
	public Dog() {
		this("汪财");
	}

	public Dog(String dogName) {
		super(dogName);
	}

	@Override
	protected String response() {
		return "汪汪!";
	}

	public void performence() {
		class Actions {
			public int times = 0;

			public void bark() {
				System.out.println("汪汪!汪汪汪!");
			}

			public void sit() {
				System.out.println("坐下了!");
			}

			public void jump() {
				System.out.println("上屋顶了!");
			}
		}
		System.out.println("----------开始表演--------------");
		Actions actions = new Actions();
		while (actions.times < 5) {
			int order = (int) Math.ceil(Math.random() * 3);
			switch (order) {
			case 1:
				actions.bark();
				break;
			case 2:
				actions.sit();
			case 3:
				actions.jump();
			}
			actions.times++;
		}
		System.out.println("----------表演结束--------------");
	}

	@Override
	public void pat() {
		Thread daze = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					System.out.println("先发个呆!");
					Thread.sleep(3000);
					System.out.println("3秒后......");
					System.out.println(response());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		});
		daze.start();
	}

}

运行效果:

总结

类是用来分组代码功能的,有时候会有一些使用范围比较小的代码,而又要对其按功能分组,就可以使用上述的实现方法。

一些细节

静态成员

本文刚开始的时候,定义的类成员都是加了static的,static表示程序一运行,这些代码就可以直接使用的,仅仅加上类名作前缀即可。如果不加就要先做new的这个动作,才能使用。也就是static与非static是两个不同的东西。因为先有static,所以在new出来的对象实例中使用static成员,反之则不能,很可能实例还没创建,没东西可用,即使他们在一个类里边。

静态类

顶层类不能加static修饰,但内部类却可以。

Lamda

匿名类有些情况下可以使用Lamda来表达,这样可以使代码更加紧凑。比如前边狗狗被的反应可以变成这样(Thead类的构造方法参数):

/**
 * 狗狗
 *
 */
public class Dog extends Pet {
	public Dog() {
		this("汪财");
	}

	public Dog(String dogName) {
		super(dogName);
	}

	@Override
	protected String response() {
		return "汪汪!";
	}

	public void performence() {
		class Actions {
			public int times = 0;

			public void bark() {
				System.out.println("汪汪!汪汪汪!");
			}

			public void sit() {
				System.out.println("坐下了!");
			}

			public void jump() {
				System.out.println("上屋顶了!");
			}
		}
		System.out.println("----------开始表演--------------");
		Actions actions = new Actions();
		while (actions.times < 5) {
			int order = (int) Math.ceil(Math.random() * 3);
			switch (order) {
			case 1:
				actions.bark();
				break;
			case 2:
				actions.sit();
			case 3:
				actions.jump();
			}
			actions.times++;
		}
		System.out.println("----------表演结束--------------");
	}

	@Override
	public void pat() {
		Thread daze = new Thread(() -> {

			try {
				System.out.println("先发个呆!");
				Thread.sleep(3000);
				System.out.println("3秒后......");
				System.out.println(response());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		});
		daze.start();
	}

}

用Lamda只要写run()中的代码就可以了。

总结

概念这东西,很多时候是用的一些新造的词来描述的,Java是一门面向对象的语言,面向对象这东西从字面上并不是很好理解。封装是什么?继承是什么?多态是什么?并不太好用自然语言来表达,多数解释也只是说明了其意图,并不能解释是如何实现的。其实代码写多了,也就那么回事。



版权声明:本文为icoolno1原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。