面向对象的个人理解(使用JAVA代码描述)

news2024/11/24 6:37:25

前言

功能分类

类(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: Mathhttps://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: Systemhttps://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: Executorshttps://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是一门面向对象的语言,面向对象这东西从字面上并不是很好理解。封装是什么?继承是什么?多态是什么?并不太好用自然语言来表达,多数解释也只是说明了其意图,并不能解释是如何实现的。其实代码写多了,也就那么回事。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/43361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ajax学习:nodejs安装+express框架介绍

ajsx应用中&#xff0c;需要安装nodejs环境 基于Chrome V8引擎&#xff08;和浏览器上的谷歌的解析引擎一样&#xff09;JavaScript运行环境 (31条消息) Node.js_安装_哇嘎123的博客-CSDN博客 查看安装是否完成 express框架介绍--为了创建一个web服务器 (31条消息) Express…

Spark系列之Spark体系架构

title: Spark系列 第四章 Spark体系架构 4.1 Spark核心功能 Alluxio 原来叫 tachyon 分布式内存文件系统Spark Core提供Spark最基础的最核心的功能&#xff0c;主要包括&#xff1a; 1、SparkContext 通常而言&#xff0c;DriverApplication的执行与输出都是通过SparkC…

STM32G491RCT6,STM32H743BIT6规格书 32bit IC MCU

STM32G4系列将强大的ArmCortex-M4加上FPU和DSP能力与丰富和先进的模拟外设相结合。它引入了两种新的数学加速器(Cordic和Filtering)&#xff0c; CAN-FD (Flexible Datarate)&#xff0c;USB Type-C接口的功率传输&#xff0c;包括物理层(PHY)和先进的安全功能。&#xff08;图…

Day38——Dp专题

DP专题 动态规划五部曲&#xff1a; 确定dp数组以及下标的含义 确定递推公式 dp数组如何初始化 确定遍历顺序 举例推导dp数组 1.斐波那契数 题目链接&#xff1a;509. 斐波那契数 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;做dp类题目&#xff0c;根据…

Meta 内部都在用的 FX 工具大起底:利用 Graph Transformation 优化 PyTorch 模型

PyTorch 中的 graph mode 在性能方面表示更为出色&#xff0c;本文介绍 Torch.FX 这个强大工具&#xff0c;可以捕捉和优化 PyTorch 程序 graph。 一、简介 PyTorch 支持两种执行模式&#xff1a;eager mode 和 graph mode。 eager mode 中&#xff0c;模型中的运算符在读取时…

JUC并发编程

目录JUC概述什么是JUC进程与线程的概念线程的状态线程的方法并发与并行管程(Monitor)用户线程和守护线程Lock接口Synchronized 关键字Synchronized 作用范围Synchronized 实现卖票例子Lock接口什么是LockLock与synchronized的区别可重入锁&#xff08;ReentrantLock&#xff09…

剑桥大学哪些专业需要IB物理成绩?

如果IB学生申请目标是剑桥大学&#xff0c;那么申请哪些专业需要学习IBDP物理课程&#xff1f;要不要学习IBDP物理课程呢&#xff1f;剑桥大学&#xff1a;IB成绩要求高&#xff0c;招录竞争激烈 在申请英国大学之前&#xff0c;理性的申请者都会提前查看一下目标大学的学术成绩…

Python破解WIFI源代码,测试成功(暴力跑字典)

目录 1&#xff0c;先安装Python环境(这个不用多说了吧) 2&#xff0c;安装PyWifi 3,自己手工整理高频弱口令&#xff0c;不建议程序生成的字典&#xff0c;生成的字典成功率实在太低。 4&#xff0c;自己生成字典的算法&#xff1a; 5&#xff0c;破解WIF代码第一种&#…

NetCore多租户开源项目,快速后台开发企业框架,赚钱就靠她了

今天给大家推荐一个开源项目&#xff0c;基于.NetCore开发的、多租户的企业开发框架。 文章目录项目简介技术架构项目结构系统功能代码生成器部分功能截图项目地址项目简介 这是一个基于.Net和Layui、基于多数据库的多租户&#xff0c;敏捷开发优选框架。系统自带权限功能、数…

面向移动支付过程中网络安全的研究与分析

基础防护系统设计 4.1.1入侵监测系统 入侵监测系统&#xff08;IDS&#xff09;的部署主要是防治外界非法人员对银行网络进行攻击&#xff0c;及时发现非法人员的入侵行为&#xff0c;以确保能够立刻采取网络阻止措施。在银行网络中的关键部位部署入侵检测系统&#xff0c;可…

springboot中controller层代码优雅写法

在基于spring框架的项目开发中&#xff0c;必然会遇到controller层&#xff0c;它可以很方便的对外提供数据接口服务&#xff0c;也是非常关键的出口&#xff0c;所以非常有必要进行规范统一&#xff0c;使其既简洁又优雅。 controller层的职责为负责接收和响应请求&#xff0c…

快手资讯|快手推出多档世界杯相关节目

1、快手直播间上线“相亲角”功能 近日&#xff0c;快手直播间上线了“相亲角”功能&#xff0c;可为主播打造相亲功能。 此外&#xff0c;快手还在“热门活动”中推出了“婚庆”频道&#xff0c;主要展示“婚礼现场”、“婚纱照”等短视频内容。企查查App显示&#xff0c;北京…

博主常用的 idea 插件,建议收藏!!!

一、Key Promoter X **快捷键提示工具&#xff1a;**每次操作&#xff0c;如果有快捷键&#xff0c;会提示用了什么快捷键。 二、Maven Helper maven 助手&#xff1a;展示 jar 包依赖关系 三、Lombok 只需加上注解 什么get set 什么toString 等等方法都不需要写 四、MyBati…

Postman下载安装注册登录简介登录后界面简介

一、为什么选择Postman? 如今&#xff0c;Postman的开发者已超过1000万(来自官网)&#xff0c;选择使用Postman的原因如下:1、简单易用 - 要使用Postman&#xff0c;你只需登录自己的账户&#xff0c;只要在电脑上安装了Postman应用程序&#xff0c;就可以方便地随时随地访问…

小程序上新(2022.11.15~11.28)

20221115 小程序基础库 2.27.3 更新 更新 框架 设备 VoIP 能力授权更新 框架 支持 worker 代码打包到小程序&小游戏分包 详情更新 组件 scroll-view 接近全屏尺寸时默认开启点击回到顶部更新 API createVKSession 在不需要用到摄像头的时候不再发起摄像头授权 详情修复 框…

elasticsearch7.6.2和logstash安装和初步

一、linux安装 参考以下链接&#xff1a; Linux&#xff08;centos7&#xff09;如何部署ElasticSearch7.6.2单节点跟集群&#xff08;es部署指南&#xff09; 二、window安装 参考下文更加详细&#xff1a;windows ElasticSearch 7.6.0集群搭建 2.1 下载elasticsearch7.6.…

开源多商户商城源码代码分析

如今&#xff0c;互联网几乎普及到了所有地区&#xff0c;同时也推动了传统行业发展。目前&#xff0c;越来越多的线下商家开始搭建多商户商城系统&#xff0c;打造属于自己的淘宝、天猫电商服务平台。什么是多商户商城系统呢&#xff1f;想必大部分人并不是很了解&#xff0c;…

多线程基本概念

多线程多线程基本概念线程控制创建终止等待分离线程安全基本概念实现互斥互斥锁死锁同步线程应用生产者与消费者模型线程池单例模式多线程基本概念 线程是进程中一个执行流程&#xff0c;是 CPU 进行执行调度的基本单元&#xff1b; 进程是系统进行资源分配的基本单元。 Linu…

SpringBoot很熟?那手撕一下自定义启动器吧

一. 前言 哈喽&#xff0c;大家好&#xff0c;不知道你有没有想辉哥呢&#xff1f;我可是很想你们哟&#xff01;最近金九银十&#xff0c;又有不少小伙伴私信辉哥&#xff0c;说自己在面试时被问到SpringBoot如何自定义启动器&#xff0c;结果自己不知道该怎么回答。那么今天…

maltose-BSA 麦芽糖-牛血清白蛋白 BSA-PEG-maltose,牛血清白蛋白-PEG-麦芽糖

maltose-BSA 麦芽糖-牛血清白蛋白 BSA-PEG-maltose,牛血清白蛋白-PEG-麦芽糖 中文名称&#xff1a;麦芽糖-牛血清白蛋白 英文名称&#xff1a;maltose-BSA 纯度&#xff1a;95% 别称&#xff1a;牛血清白蛋白修饰麦芽糖&#xff0c;BSA-麦芽糖 麦芽糖-聚乙二醇-牛血清白…