Chapter08 面向对象(中级)

8.1 IDEA的使用

1. 快捷键

  1. 删除当前行, 默认是 ctrl + Y 自己配置 ctrl + d
  2. 复制当前行, 自己配置 ctrl + alt + 向下光标
  3. 补全代码 alt + /
  4. 添加注释和取消注释 ctrl + / 【第一次是添加注释,第二次是取消注释】
  5. 导入该行需要的类 先配置 auto import , 然后使用 alt+enter 即可
  6. 快速格式化代码 ctrl + alt + L
  7. 快速运行程序 自己定义 shift + F10
  8. 生成构造器等 alt + insert [提高开发效率]
  9. 查看一个类的层级关系 ctrl + H [学习继承后,非常有用]
  10. 将光标放在一个方法上,输入 ctrl + B , 可以定位到方法 [学继承后,非常有用]
  11. 自动的分配变量名 , 通过 在后面假 .var [老师最喜欢的]

8.2 包

命名规则:

  • 只能包含数字、字母、下划线、小圆点..但不能用数字开头,不能是关键字或保留字

命名规范:

  • 一般是小写字母+小圆点一般是com.公司名.项目名.业务模块名

常用的包:

  • 一个包下,包含很多的类,java 中常用的包有:
  1. java.lang.* //lang 包是基本包,默认引入,不需要再引入.
  2. java.util.* //util 包,系统提供的工具包, 工具类,使用 Scanner
  3. java.net.* //网络包,网络开发
  4. java.awt.* //是做 java 的界面开发,GUI
//package 的作用是声明当前类所在的包,需要放在类(或者文件)的最上面,
// 一个类中最多只有一句 package
package com.lxd.pkg; //import 指令 位置放在 package 的下面,在类定义前面,可以有多句且没有顺序要求
import java.util.Scanner;
import java.util.Arrays;
//... //类定义
public class PkgDetail {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] arr = {0, -1, 1};
Arrays.sort(args);
}
}

8.3 访问修饰符

  • java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围)
  1. 公开级别:用 public 修饰,对外公开
  2. 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
  3. 默认级别:没有修饰符号,向同一个包的类公开.
  4. 私有级别:用 private 修饰,只有类本身可以访问,不对外公开.

8.3.1 注意事项

  1. 修饰符可以用来修饰类中的属性,成员方法以及类
  2. 只有默认的和public才能修饰类!,并且遵循上述访问权限的特点
  3. 因为没有学习继承,因此关于在子类中的访问权限,我们讲完子类后,在回头讲解
  4. 成员方法的访问规则和属性完全一样.
package com.lxd.modifier;

public class A {
//四个属性,
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400; ////在同一类中,可以访问 public protected 默认 private
public void m1(){
System.out.println("n1=" + n1 + "n2=" + n2 + "n3=" + n3 + "n4=" + n4) ;
}
protected void m2(){
}
void m3(){
}
private void m4(){
}
}
package com.lxd.modifier;

public class Test {
public static void main(String[] args) {
A a = new A();
a.m1();
B b = new B();
b.say(); a.m1();
a.m2();
a.m3();
// a.m4(); 错误,私有类不可以在别的类使用
}
}
//只有 默认 和 public 可以修饰类
class T{ }
package com.lxd.pkg;

import com.lxd.modifier.A;

public class Test {
public static void main(String[] args) {
A a = new A();
//在不同包下,可以访问public
System.out.println(a.n1 );
a.m1();//这里可以使用public的方法
}
}
package com.lxd.modifier;

public class B {
public void say(){
A a = new A();
//在同一个包下,可以访问 public ,protected 和 默认 ,不能访问private
System.out.println("n1=" + a.n1 + " n2=" + a.n2 + "n3=" + a.n3);
}
}

8.4 面向对象编程 - 封装

8.4.1 封装的实现步骤 (三步)

  • 介绍:

    封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。

  1. 将属性进行私有化 private 【不能直接修改属性】
  2. 提供一个公共的(public) set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){//Xxx表示某个属性
//加入数据验证的业务逻辑
属性 = 参数名;
}

3.提供一个公共的(public) get方法,用于获取属性的值

public XX getXxx(){//权限判断
return xx;
}

快速入门

package com.lxd.encap;

public class encapsulation01 {
public static void main(String[] args) {
//如果要使用快捷键 alt+r, 需要先配置主类
//第一次,我们使用鼠标点击形式运算程序,后面就可以用
Person person = new Person();
person.setName("韩顺平");
person.setAge(30);
person.setSalary(30000);
System.out.println(person.info());
System.out.println(person.getSalary());
//如果我们自己使用构造器指定属性
Person smith = new Person("smith", 80, 50000);
System.out.println("====smith 的信息======");
System.out.println(smith.info());
}
}
/*
那么在 java 中如何实现这种类似的控制呢?
请大家看一个小程序(com.lxd.encap: Encapsulation01.java), 不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认
年龄, 必须在 1-120, 年龄, 工资不能直接查看 , name 的长度在 2-6 字符 之间
*/
class Person {
public String name; //名字公开
private int age; //age 私有化
private double salary; //.. public void say(int n,String name) {
}
//构造器 alt+insert
public Person() {
}
//有三个属性的构造器
public Person(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
//我们可以将 set 方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
//自己写 setXxx 和 getXxx 太慢,我们使用快捷键
//然后根据要求来完善我们的代码.
public String getName() {
return name;
}
public void setName(String name) {
//加入对数据的校验,相当于增加了业务逻辑
if(name.length() >= 2 && name.length() <=6 ) {
this.name = name;
}else {
System.out.println("名字的长度不对,需要(2-6)个字符,默认名字");
this.name = "无名人";
}
}
public int getAge() {
return age;
}
public void setAge(int age){
//判断
if(age >= 1 && age <= 120) {//如果是合理范围
this.age = age;
} else {
System.out.println("你设置年龄不对,需要在 (1-120), 给默认年龄 18 ");
this.age = 18;//给一个默认年龄
}
}
public double getSalary() {
//可以这里增加对当前对象的权限判断
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//写一个方法,返回属性信息
public String info() {
return "信息为 name=" + name + " age=" + age + " 薪水=" + salary;
}
}

课堂练习

package com.lxd.encap;

public class Account {
/**
* 创建程序,在其中定义两个类:Account 和 AccountTest 类体会 Java 的封装性。
* Account 类要求具有属性:姓名(长度为 2 位 3 位或 4 位)、余额(必须>20)、
* 密码(必须是六位), 如果不满足,则给出提示信息,并给默认值(程序员自己定)
* 通过 setXxx 的方法给 Account 的属性赋值。
* 在 AccountTest 中测试
*/
private String name;
private double balance;
private String pwd; public Account() {
} public Account(String name, double balance, String pwd) {
setBalance(balance);
setName(name);
setPwd(pwd);
} public String getName() {
return name;
} public void setName(String name) {
if (name.length() >= 2 && name.length() <= 4){
this.name = name;
} else {
System.out.println("你输入的名字有误,请重新输入(2 - 4 位)");
} } public double getBalance() {
return balance;
} public void setBalance(double balance) {
if (balance > 20) {
this.balance = balance;
} else {
System.out.println("余额不足20");
}
} public String getPwd() {
return pwd;
} public void setPwd(String pwd) {
if (pwd.length() == 6) {
this.pwd = pwd;
} else {
System.out.println("密码不足六位,请重新输入");
this.pwd = "000000";
}
}
public void info(){
System.out.println("名字=" + this.name + " 余额=" + this.balance + " 密码=" + this.pwd);
}
}
package com.lxd.encap;

public class AccountTest {
public static void main(String[] args) {
Account account = new Account("lxd",25,"123456");
account.info();
}
}

8.5 面向对象编程 - 继承

8.5.1 基本介绍和示意图

  • 继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。画出继承的示意图

8.5.2 快速入门

package com.lxd.extends_;
//父类
public class Students {
public String name;
public int age;
private double scores; public void setScores(double scores) {
this.scores = scores;
}
public void showInfo(){
System.out.println("名字=" + name + " 年龄=" + age + " 分数=" + scores);
}
}
package com.lxd.extends_;
//继承父类
public class Pupils extends Students {
public void testing() {
System.out.println("小学生 " + name + " 正在考小学数学..");
}
}
package com.lxd.extends_;
//继承父类
public class Graduate extends Students{
public void testing() {
System.out.println("大学生 " + name + " 正在考大学数学..");
}
}

8.5.3 继承细节

  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
  2. 子类必须调用父类的构造器, 完成父类的初始化
  3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过(怎么理解。) [举例说明]
  4. 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
  5. super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
  6. super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
  7. java 所有类都是 Object 类的子类, Object 是所有类的基类.
  8. 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
  9. 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。 思考:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】
  10. 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系
package com.lxd.extends_;

public class TopBase { //父类Object

    public TopBase() {
//super()Object的无参构造器
System.out.println("TopBase()构造器被调用");
}
}
package com.lxd.extends_;

public class Base extends TopBase {
//四个属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400; public Base() {//无参构造器
System.out.println("父类Base()....构造器被调用");
}
public Base(String name, int age){//有参构造器
//默认的super()
System.out.println("父类Base(String name, int age)构造器被调用");
}
public Base(String name){//有参构造器
System.out.println("父类Base(String name)构造器被调用");
} //父类提供一个public的方法,返回n4
public int getN4() {
return n4;
} public void test100() {
System.out.println("test100");
} public void test200() {
System.out.println("test200");
} protected void test300() {
System.out.println("test300");
} private void test400() {
System.out.println("test400");
} //call
public void callTest400() {
test400();
} }
package com.lxd.extends_;

public class Sub extends Base {
public Sub(String name,int age) {
//1.老师调用父类的无参构造器,如下或者,什么都不写,默认就是调用super()
//super();//父类的无参构造器
//2.调用父类的 Base(String name)这个构造器
//super("jack");
//3.调用父类的 Base(String name, int age) 这个构造器
//super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
//super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
super("joker",20);
System.out.println("子类Sub(String name,int age)构造器被调用");
}
public Sub(){//无参构造器
// super();//默认调用父类的无参构造器
super("joker",10);
System.out.println("子类sub()...构造器被调用");
} // 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
//如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不通过 public Sub(String name) { //有参构造器
super("smith",20);
//do nothing
System.out.println("子类Sub(String name)...构造器被调用");下·
} public void sayOk() { //子类方法
//非私有的属性和方法可以在子类直接访问
//但是私有属性和方法不能在子类直接访问
System.out.println(n1 + " " + n2 + " " + n3);
test100();
test200();
test300();
//test400(); 错误的
//要通过父类提供公共的方法去访问
System.out.println("n4=" + getN4());
callTest400();
}
}
package com.lxd.extends_;

public class ExtendsDetail {
public static void main(String[] args) {
System.out.println("====第一个对象====");
Sub sub = new Sub();//创建子类对象,sub
System.out.println("====第二个对象====");
Sub sub2 = new Sub("jake");//创建第二个对象
System.out.println("====第三个对象====");
Sub sub3 = new Sub("king",10);//创建第三个对象
}
}

8.5.4 继承的本质 (重要)

package com.lxd.extends_;

public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son(); //内存的布局
//?-> 这时请大家注意,要按照查找关系来返回信息
// (1) 首先看子类是否有该属性
// (2) 如果子类有这个属性,并且可以访问,则返回信息
// (3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
// (4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object...
System.out.println(son.name);//返回就是大头儿子
// System.out.println(son.age);//返回的就是 39
System.out.println(son.getAge());//返回的就是 39
System.out.println(son.hobby);//返回的就是旅游
}
}
class GrandPa{ //爷爷类
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa { //父类
String name = "大头爸爸";
private int age = 39; public int getAge() { //在父类里写一个公有的方法
return age;
}
}
class Son extends Father{ //子类
String name = "大头儿子";
}

练习

package com.lxd.extends_.exercise;

public class ExtendsExercise02 {
public static void main(String[] args) {
C c = new C();
}
} class A02 {//A02 类 public A02() {
System.out.println("我是 A02 类");
}
} class B02 extends A02 { //B02 类,继承 A02 类 //main 方法中: C c =new C(); 输出么内容? 3min
public B02() {
System.out.println("我是 B02 类的无参构造");
} public B02(String name) {
//有一个默认的super构造器
System.out.println(name + "我是 B02 类的有参构造");
}
} class C extends B02 { //C 类,继承 B 类
public C() {
this("hello");
System.out.println("我是 c 类的无参构造");
} public C(String name) {
super("lxd");
System.out.println("我是 c 类的有参构造");
}
}

8.6 super关键字

8.6.1 基本介绍

  • super 代表父类的引用,用于访问父类的属性、方法、构造器

8.6.2 基本语法

  1. 访问父类的属性,但不能访问父类的private属性[案例]

    super.属性名;

  2. 访问父类的方法,不能访问父类的private方法

    super.方法名(参数列表);

  3. 访问父类的构造器(这点前面用过):

    super(参数列表);只能放在构造器的第一句,只能出现一句!

package com.lxd.super_;

public class A { //父类
//四个属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400; public A() {
} public A(String name,int age){ } public void test100() {
} protected void test200() {
} void test300() {
} private void test400() {
}
}
package com.lxd.super_;

public class B extends A{
// 访问父类的属性,但不能访问父类的private属性[案例]super.属性名;
public void hi(){
System.out.println("super.n1" + " " + super.n2 + " " + super.n3);
} // 访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
public void ok(){
super.test100();
super.test200();
super.test300();
// super.test400(); //不能访问父类private方法
}
// 访问父类的构造器(这点前面用过) super(参数列表);只能放在构造器的第一句,只能出现一句!
public B(){
//super();
//super("jack",20); 调用的是A类的这个构造器 public A(String name,int age){
}
}

8.6.3 super细节

  1. 调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)

  2. 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果![举例]

  3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则

8.7 方法重写/覆盖(OverRide)

8.7.1 基本介绍

  • 简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法

8.7.2 细节

  1. 子类的方法的形参列表,方法名称,要和父类方法的形参列表,方法名称完全一样。【演示】
  2. 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类,比如父类返回类型是Object,子类方法返回类型是String【演示】
  3. 子类方法不能缩小父类方法的访问权限【演示】public > protected >默认>private
package com.lxd.OverRide;

public class Animal {
public void cry() {
System.out.println("动物叫唤..");
} public Object m1() {
return null;
} public String m2() {
return null;
} public AAA m3() {
return null;
} protected void eat() {
}
}
package com.lxd.OverRide;

public class Dog extends Animal {
//老韩解读
//1. 因为 Dog 是 Animal 子类
//2. Dog 的 cry 方法和 Animal 的 cry 定义形式一样(名称、返回类型、参数)
//3. 这时我们就说 Dog 的 cry 方法,重写了 Animal 的 cry 方法
public void cry() {
System.out.println("小狗汪汪叫..");
} //细节: 子类方法的返回类型和父类方法返回类型一样,
// 或者是父类返回类型的子类
// 比如 父类
// 返回类型是 Object, // 子类方法返回类型是 String public String m1() {
return null;
} //这里 Object 不是 String 的子类,因此编译错误
// public Object m2() {
// return null;
// }
// public BBB m3() {
// return null;
// }
//细节: 子类方法不能缩小父类方法的访问权限 【演示】
//public > protected > 默认>private
public void eat() {
}
} class AAA {
} class BBB extends AAA {
}
package com.lxd.OverRide;

public class Override01 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.cry();
}
}

8.8 面向对象编程 - 多态 (polymorphic)

8.8.1 基本介绍

  • 方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

8.8.2 多态的具体体现

1. 方法的多态:重写和重载就体现多态

package com.hspedu.poly_;

public class PloyMethod {
public static void main(String[] args) {
//方法重载体现多态
A a = new A();
//这里我们传入不同的参数,就会调用不同 sum 方法,就体现多态
System.out.println(a.sum(10, 20));
System.out.println(a.sum(10, 20, 30));
//方法重写体现多态
B b = new B();
a.say();
b.say();
}
} class B { //父类
public void say() {
System.out.println("B say() 方法被调用...");
}
} class A extends B {//子类 public int sum(int n1, int n2) {//和下面 sum 构成重载
return n1 + n2;
} public int sum(int n1, int n2, int n3) {
return n1 + n2 + n3;
} public void say() {
System.out.println("A say() 方法被调用...");
}
}

2. 对象的多态 (核心,困难,重点)

  1. 一个对象的编译类型和运行类型可以不一致
  2. 编译类型在定义对象时,就确定了,不能改变
  3. 运行类型是可以变化的.
  4. 编译类型看定义时 = 号的左边,运行类型看 = 号的右边
package com.lxd.polymorphic.objectpoly;

public class PolyObject {//运行
public static void main(String[] args) {
//体验对象多态特点
//animal 编译类型就是 Animal , 运行类型 Dog
Animal animal = new Dog();
//因为运行时 , 执行到改行时,animal 运行类型是 Dog,所以 cry
animal.cry(); //animal 编译类型 Animal,运行类型就是 Cat
animal = new Cat();
animal.cry();
}
}
package com.lxd.polymorphic.objectpoly;

public class Animal {//父类
public void cry(){
System.out.println("Animal cry() 动物叫。");
}
}
=======================================================
package com.lxd.polymorphic.objectpoly; public class Cat extends Animal{//子类
@Override
public void cry() {
System.out.println("Cat cay() 小猫叫");
}
}
=======================================================
package com.lxd.polymorphic.objectpoly; public class Dog extends Animal{//子类
@Override
public void cry() {
System.out.println("Dog cry() 小狗叫");
}
}

8.8.3 多态注意事项和细节讨论

  • 多态的前提是:两个对象(类)存在继承关系

1. 多态的向上转型

  1. 本质:父类的引用指向了子类的对象
  2. 语法:父类类型 引用名 = new 子类类型();
  3. 特点:编译类型看左边,运行类型看右边。
  4. 可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员;
  5. 最终运行效果看子类的具体实现!

2. 多态的向下转型

  1. 语法:子类类型 引用名 = (子类类型) 父类引用
  2. 只能强转父类的引用,不能强转父类的对象
  3. 要求父类的引用必须指向的是当前目标类型的对象
  4. 当向下转型后,可以调用子类类型中所有的成员
package com.hspedu.poly_.detail_;
public class Animal {
String name = "动物";
int age = 10;
public void sleep(){
System.out.println("睡");
}
public void run(){
System.out.println("跑");
}
public void eat(){
System.out.println("吃");
}
public void show(){
System.out.println("hello,你好");
}
}
package com.hspedu.poly_.detail_;
public class Cat extends Animal {//子类
public void eat(){//方法重写
System.out.println("猫吃鱼");
}
public void catchMouse(){//Cat 特有方法
System.out.println("猫抓老鼠");
}
}
package com.hspedu.poly_.detail_;
public class Dog extends Animal {//Dog 是 Animal 的子类
}
package com.hspedu.poly_.detail_;
public class PolyDetail {
public static void main(String[] args) {
//向上转型: 父类的引用指向了子类的对象
//语法:父类类型引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类
//向上转型调用方法的规则如下:
//(1)可以调用父类中的所有成员(需遵守访问权限)
//(2)但是不能调用子类的特有的成员
//(3)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
//animal.catchMouse();错误
//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
//,然后调用,规则我前面我们讲的方法调用规则一致。
animal.eat();//猫吃鱼.. animal.run();//跑
animal.show();//hello,你好
animal.sleep();//睡
//老师希望,可以调用 Cat 的 catchMouse 方法
//多态的向下转型
//(1)语法:子类类型 引用名 =(子类类型)父类引用;
//问一个问题? cat 的编译类型 Cat,运行类型是 Cat
Cat cat = (Cat) animal;
cat.catchMouse();//猫抓老鼠
//(2)要求父类的引用必须指向的是当前目标类型的对象
Dog dog = (Dog) animal; //可以吗?不可以,对象不一致
System.out.println("ok~~");
}
}

3. 属性没有重写之说!属性的值看编译类型,属性的方法看运行类型

package com.hspedu.poly_.detail_;
public class PolyDetail02 {
public static void main(String[] args) {
//属性没有重写之说!属性的值看编译类型
Base base = new Sub();//向上转型
System.out.println(base.count);// ? 看编译类型 10
Sub sub = new Sub();
System.out.println(sub.count);//? 20
}
}
class Base { //父类
int count = 10;//属性
}
class Sub extends Base {//子类
int count = 20;//属性
}

4. instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型

package com.hspedu.poly_.detail_;
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
//aa 编译类型 AA, 运行类型是 BB
//BB 是 AA 子类
AA aa = new BB();
System.out.println(aa instanceof AA);
System.out.println(aa instanceof BB);
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA {} //父类
package com.hspedu.poly_.detail_;
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
//aa 编译类型 AA, 运行类型是 BB
//BB 是 AA 子类
AA aa = new BB();
System.out.println(aa instanceof AA);
System.out.println(aa instanceof BB);
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA {} //父类
class BB extends AA {}//子类

5. 练习

public class PolyExercise01 {
public static void main(String[] args) {
double d = 13.4;//ok
long l = (long) d;//ok
System.out.println(l);//13
int in = 5;//ok
// boolean b = (boolean) in; //不对,boolean -> int
Object obj = "Hello";//可以,向上转型
String objStr = (String) obj;//可以,向下转型
System.out.println(objStr);// hello
Object objPri = new Integer(5);//可以,向上转型
//错误ClassCastExcetpion,指向lnteger的父类引用,转成String
String str = (String) objPri;
Integer str1 = (Integer) objPri;//可以,向下转型
}
}
package com.lxd.polymorphic.excise01;

public class PolyExercise02 {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20
Base b = s;
System.out.println(b == s);//true
System.out.println(b.count);//10
b.display();//20
}
}
============================================
package com.lxd.polymorphic.excise01; public class Base {//父类
int count = 10;
public void display(){
System.out.println(this.count);
}
}
============================================
package com.lxd.polymorphic.excise01; public class Sub extends Base {//父类
int count = 20;
public void display(){
System.out.println(this.count);
}
}

6. java的动态绑定机制(非常非常重要)

  • java的动态绑定机制

    1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
    2. 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用
package com.lxd.polymorphic.dynamic;

public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型A,运行类型B
A a = new B();//向上转型
System.out.println(a.sum());//30
System.out.println(a.sum1());//20
}
} class A {//父类
public int i = 10; //动态绑定机制
public int sum() {
return getI() + 10;//当子类没有sum方法,在父类发现有,调用,然后发现其中还有方法(父类和子类都有的话就看对象的运行类型是谁,就去那里调用),
} public int sum1() {
return i + 10;//对象属性不会有动态绑定机制
} public int getI() {
return i;
}
} class B extends A {
public int i = 20; // public int sum() {
// return i + 20;
// } public int getI() {
return i;
} // public int sum1() {
// return i + 10;
// }
}

7. 多态的应用

① 多态数组
  • 数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
/*应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组
中,并调用每个对象
say 方法
*/
package com.lxd.polymorphic.polyarr; public class PolyArray {//运行
public static void main(String[] args) {
Person[] people = new Person[5];
people[0] = new Person("jack",20);
people[1] = new Student("mary",23,88.5);
people[2] = new Student("smith",19, 30);
people[3] = new Teacher("scott",30, 20000);
people[4] = new Teacher("king", 50,25000); ////循环遍历多态数组,调用 say
for (int i = 0 ; i < people.length;i++){
//老师提示: person[i] 编译类型是 Person ,运行类型是是根据实际情况有 JVM 来判
System.out.println(people[i].say());
if (people[i] instanceof Student){ //判断 person[i] 的运行类型是不是 Student
Student student = (Student)people[i];//向下转型
student.study();
//小伙伴也可以使用一条语句 ((Student)persons[i]).study();
} else if(people[i] instanceof Teacher){
((Teacher)people[i]).teach();
}else if(people[i] instanceof Person){
//System.out.println("你的类型有误, 请自己检查...");
}else {
System.out.println("你的类型有误, 请自己检查...");
}
}
}
}
package com.lxd.polymorphic.polyarr;

public class Person {//父类
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
} public void setAge(int age) {
this.age = age;
} public int getAge() {
return age;
} public void setName(String name) {
this.name = name;
} public String getName() {
return name;
}
public String say() {//返回名字和年龄
return "姓名" + name + "\t" + "年龄" + age;
}
}
=======================================================
package com.lxd.polymorphic.polyarr; public class Student extends Person { //子类
private double score; public Student(String name, int age,double score) {
super(name, age);
this.score = score;
} public void setScore(double score) {
this.score = score;
} public double getScore() {
return score;
}
public String say(){
return "学生" + super.say() + "成绩" + getScore();
}
//特有的方法
public void study() {
System.out.println("学生 " + getName() + " 正在学 java...");
}
}
======================================================
package com.lxd.polymorphic.polyarr; public class Teacher extends Person{ //子类
private double salary ; public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
} public double getSalary() {
return salary;
} public void setSalary(double salary) {
this.salary = salary;
}
public String say(){
return "老师" + super.say() + "薪水" + salary;
}
//特有方法
public void teach() {
System.out.println("老师 " + getName() + " 正在讲 java 课程...");
}
}
② 多态参数
/*
定义员工类Employee,包含姓名和月工资[private], 以及计算年工资getAnnual的方法。普通员工和经理继承了员工,经理类多了奖金bonus属性和管理manage方法,普通员工类多了work方法,普通员工和经理类要求分别重写getAnnual方法
测试类中添加一个方法showEmpAnnual(Employee e),实现获取任何员工对象的年工资,并在main方法中调用该方法[e.getAnnual0]
测试类中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法1/眼高手低..
*/
package com.lxd.polymorphic.polyparameter; public class polyParameter {
public static void main(String[] args) {
Worker tom = new Worker("tom", 2500);
Manager smith = new Manager("smith", 5000, 20000);
polyParameter polyParameter = new polyParameter(); polyParameter.showEmpAnnual(tom);
polyParameter.showEmpAnnual(smith); polyParameter.testWork(tom);
polyParameter.testWork(smith); }
//实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [e.getAnnual()]
public void showEmpAnnual(Employee e){
System.out.println(e.getAnnual());
}
//添加一个方法,testWork,如果是普通员工,则调用 work 方法,如果是经理,则调用 manage 方法
public void testWork(Employee e){
if (e instanceof Worker){
((Worker)e).work();
} else if (e instanceof Manager){
((Manager)e).manage();
} else {
System.out.println("不做处理");
}
}
}
package com.lxd.polymorphic.polyparameter;

public class Employee {
private String name ;
private double salary; public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public double getAnnual(){
return 12 * salary;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public double getSalary() {
return salary;
} public void setSalary(double salary) {
this.salary = salary;
}
}
=================================
package com.lxd.polymorphic.polyparameter; public class Manager extends Employee {
private double bonus; public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
public void manage(){
System.out.println("经理" + getName() + "正在管理。。");
} @Override
public double getAnnual() {
return super.getAnnual() + bonus;
}
}
============================================
package com.lxd.polymorphic.polyparameter; public class Worker extends Employee{
public Worker(String name, double salary) {
super(name, salary);
}
public void work(){
System.out.println("普通工人" + getName() + "正在工作");
} @Override
public double getAnnual() {//因为普通员工没有其它收入,则直接调用父类方法
return super.getAnnual();
}
}

8.9 Object类

8.9.1 equals方法

==== 是一个比较运算符==

  1. ==: 既可以判断基本类型,又可以判断引用类型
  2. ==: 如果判断基本类型,判断的是值是否相等。示例:int i = 10; double d = 10.0;
  3. ==: 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象【案例说明】
  4. equals: 是Object类中的方法,只能判断引用类型,如何看Jdk源码,看老师演示:
  5. 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如 Integer.String【看看String和 Integer的equals源代码】
package com.hspedu.object_;
public class Equals01 {
public static void main(String[] args) {
A a = new A();
A b = a;
A c = b;
System.out.println(a == c);//true
System.out.println(b == c);//true
B bObj = a;
System.out.println(bObj == c);//true
int num1 = 10;
double num2 = 10.0;
System.out.println(num1 == num2);//基本数据类型,判断值是否相等
//equals 方法,源码怎么查看. //把光标放在 equals 方法,直接输入 ctrl+b
//如果你使用不了. 自己配置. 即可使用. /*
//带大家看看 Jdk 的源码 String 类的 equals 方法
//把 Object 的 equals 方法重写了,变成了比较两个字符串值是否相同
/*
public boolean equals(Object anObject) {
if (this == anObject) {//如果是同一个对象
return true;//返回 true
}
if (anObject instanceof String) {//判断类型
String anotherString = (String)anObject;//向下转型
int n = value.length;
if (n == anotherString.value.length) {//如果长度相同
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {//然后一个一个的比较字符
if (v1[i] != v2[i])
return false;
i++;
}
return true;//如果两个字符串的所有字符都相等,则返回 true
}
}
return false;//如果比较的不是字符串,则直接返回 false
}
*/
"hello".equals("abc");
//看看 Object 类的 equals 是
/*
//即 Object 的 equals 方法默认就是比较对象地址是否相同
//也就是判断两个对象是不是同一个对象. public boolean equals(Object obj) {
return (this == obj);
}
*/
/*
//从源码可以看到 Integer 也重写了 Object 的 equals 方法, //变成了判断两个值是否相同
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
*/
Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
System.out.println(integer1 == integer2);//false
System.out.println(integer1.equals(integer2));//true
String str1 = new String("hspedu");
String str2 = new String("hspedu");
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//true
}
}
class B {}
class A extends B {}

8.9.2 重写equals

package com.hspedu.object_;
public class EqualsExercise01 {
public static void main(String[] args) {
Person person1 = new Person("jack", 10, '男');
Person person2 = new Person("jack", 20, '男');
System.out.println(person1.equals(person2));//假
}
}
//判断两个 Person 对象的内容是否相等,
//如果两个 Person 对象的各个属性值都一样,则返回 true,反之 false
class Person{ //extends Object
private String name;
private int age;
private char gender;
//重写 Object 的 equals 方法
public boolean equals(Object obj) {
//判断如果比较的两个对象是同一个对象,则直接返回 true
if(this == obj) {
return true;
}
//类型判断
if(obj instanceof Person) {//是 Person,我们才比较
//进行 向下转型, 因为我需要得到 obj 的 各个属性
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
}
//如果不是 Person ,则直接返回 false
return false;
}
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}

练习

package com.hspedu.object_;
public class EqualsExercise02 {
public static void main(String[] args) {
Person_ p1 = new Person_();
p1.name = "hspedu";
Person_ p2 = new Person_();
p2.name = "hspedu";
System.out.println(p1==p2); //False
System.out.println(p1.name .equals( p2.name));//T
System.out.println(p1.equals(p2));//False
String s1 = new String("asdf");
String s2 = new String("asdf");
System.out.println(s1.equals(s2));//T
System.out.println(s1==s2); //F
}
}
class Person_{//类
public String name;
}
       public class EqualsExercise03 {
int it = 65;
float fl = 65.0f;
System.out.println("65 和 65.0f 是否相等?" + (it == fl));T
char ch1 = ‘A’; char ch2 = 12;
System.out.println(“65 和‘A’是否相等?” + (it == ch1));//T
System.out.println(“12 和 ch2 是否相等?” + (12 == ch2));//T
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("str1 和 str2 是否相等?"+ (str1 == str2)); //F
System.out.println(“str1 是否 equals str2?”+(str1.equals(str2)));//T
System.out.println(“hello” == new java.sql.Date()); //编译错误
}

小总结:equals

  • 在 Object 中 equals 方法默认判断就是比较对象的地址是否相同

  • 在子类重写中的 equals 方法,判断就是比较对象的值是否相同(子类,例如String,Integer)

  • 如果是自己写的子类,则没有重写的 equals 方法,需要自己写一个

  • Person_ p1 = new Person_();

    p1.name = "hspedu";

    Person_ p2 = new Person_();

    p2.name = "hspedu";

    System.out.println(p1.name .equals( p2.name));//T,这里比较的是属性,使用的子类String类型中的equals,自然就为TRUE

8.9.3 hashCode 方法

  1. 提高具有哈希结构的容器的效率!
  2. 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
  3. 两个引用,如果指向的是不同对象,则哈希值是不一样的
  4. 哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址
  5. 案例演示[HashCode_.java]: obj.hashCode() [ 测试:A obj1 = new A(); A obj2 = new A(); A obj3 = obj1 ]
  6. 后面在集合,中 hashCode 如果需要的话,也会重写, 在讲解集合时,老韩在说如何重写 hashCode

8.9.4 toString 方法

  • 基本介绍 默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】 子类往往重写 toString 方法,用于返回对象的属性信息
  • 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式
  • 当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用 monster.toString()
package com.hspedu.object_;
public class ToString_ {
public static void main(String[] args) {
/*
Object 的 toString() 源码
(1)getClass().getName() 类的全类名(包名+类名 )
(2)Integer.toHexString(hashCode()) 将对象的 hashCode 值转成 16 进制字符串
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
*/
Monster monster = new Monster("小妖怪", "巡山的", 1000);
System.out.println(monster.toString() + " hashcode=" + monster.hashCode());
System.out.println("==当直接输出一个对象时,toString 方法会被默认的调用==");
System.out.println(monster); //等价 monster.toString()
}
}
class Monster {
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
//重写 toString 方法, 输出对象的属性
//使用快捷键即可 alt+insert -> toString
@Override
public String toString() { //重写后,一般是把对象的属性值输出,当然程序员也可以自己定制
return "Monster{" +
"name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
@Override
protected void finalize() throws Throwable {
System.out.println("fin..");
}
}

8.9.5 finalize 方法

  1. 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作【演示】
  2. 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来 销毁该对象,在销毁该对象前,会先调用 finalize 方法。
  3. 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制,测 试:Car [name]
package com.hspedu.object_;
//演示 Finalize 的用法
public class Finalize_ {
public static void main(String[] args) {
Car bmw = new Car("宝马");
//这时 car 对象就是一个垃圾,垃圾回收器就会回收(销毁)对象, 在销毁对象前,会调用该对象的 finalize 方法
//,程序员就可以在 finalize 中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)
//,如果程序员不重写 finalize,那么就会调用 Object 类的 finalize, 即默认处
//,如果程序员重写了 finalize, 就可以实现自己的逻辑
bmw = null;
System.gc();//主动调用垃圾回收器
System.out.println("程序退出了....");
}
}
class Car {
private String name;
//属性, 资源。。
public Car(String name) {
this.name = name;
}
//重写 finalize
@Override
protected void finalize() throws Throwable {
System.out.println("我们销毁 汽车" + name );
System.out.println("释放了某些资源...");
}
}

8.10 零钱通

package com.lxd.smallchange.oop;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner; /*
该类是完成零钱通的各个功能的类
使用oop(面向对象编程)
将各个功能对应一个方法 */
public class SmallChangeSysOOP {
//属性
//初始化变量
boolean loop = true;
Scanner scanner = new Scanner(System.in);
String key = ""; //2.完成零钱通明细
String details = "============零钱通明细============"; //3.完成收益入账 完成功能驱动程序员增加新的变量和代码
//定义新的变量
double money = 0;
double balance = 0;
Date date = null; //date 是 java.util.Date类型,表示日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");//可以用于日期和石化的 //4.消费,定义新变量,保存消费的原因
String note = ""; //5.退出
String choice = ""; //先完成显示菜单,并可以选择
public void mainMenu() {
do {
System.out.println("\n============选择零钱通============");
System.out.println("\t\t1 零钱通明细");
System.out.println("\t\t2 收益入账");
System.out.println("\t\t3 消 费");
System.out.println("\t\t4 退 出"); System.out.println("请输入你的选择 1 - 4 :");
key = scanner.next(); switch (key) {
case "1":
this.detail();
break;
case "2":
this.income();
break;
case "3":
this.pay();
break; case "4":
this.exit();
break;
}
} while (loop);
} //完成零钱通的明细
public void detail() {
System.out.println(details);
} //完成收益入账
public void income() {
System.out.println("收益入账金额:");
money = scanner.nextDouble();
//money 的值范围应该校验
//找出不正确的金额条件,然后给出提示,直接return
if (money <= 0) {
System.out.println("收益入账金额需要 大于 0");
return;
}
balance += money; //拼接收益入账信息到 details
date = new Date();//获取当前日期
details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + balance;
} //消费
public void pay() {
System.out.println("消费金额:");
money = scanner.nextDouble();
//money 的值范围应该校验
if (money > balance || money <= 0) {
System.out.println("你的消费应该在0 - " + balance);
return;
}
System.out.println("消费说明:");
note = scanner.next();
balance -= money; date = new Date();//获取当前日期 details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + balance; } //退出退出时,给出提示“你确定要退出吗? y/n“必须输入正确的y/n
//否则循环输入指令,直到输入y/n
//(1)定义一个变量 choice,接收用户的输入
//(2)使用 while + break,来处理接收到的输入时 y 或者 n
//(3)退出while后,在判断choice是y还是n,就可以决定是否退出
//(4)建议一段代码,完成一个功能,尽量不要混在一起
public void exit() {
//用户输入4
while (true) {
System.out.println("请问你是否要退出 y/n");
choice = scanner.next();
if ("y".equals(choice) || "n".equals(choice)) {
break;
}
}
if (choice.equals("y")) {
loop = false;
return;
} else if (choice.equals("n")) {
return;
}
}
}
package com.lxd.smallchange.oop;

public class SmallChangeSysApp {
public static void main(String[] args) {
//直接调用SmallChangeSysOOP
new SmallChangeSysOOP().mainMenu();
}
}

8.11 本章作业

需要源码,可以找我呀!!(新人,不喜勿喷,谢谢)

Chapter08 面向对象(中级)的更多相关文章

  1. python 面向对象-笔记

    1.如何创建类 class 类名: pass class bar: pass 2.创建方法 构造方法,__init__(self,arg) obj = 类('a1') 普通方法 obj = 类(‘xx ...

  2. Chapter09 项目

    Chapter09 项目 房屋出租系统(面向对象中级) 9.1 房屋出租系统-需求 9.1.1项目需求说明 实现基于文本界面的<房屋出租软件>. 能够实现对房屋信息的添加.修改和删除(用数 ...

  3. Python 第六篇(中):面向对象编程中级篇

    面向对象编程中级篇: 编程思想概述: 面向过程:根据业务逻辑从上到下写垒代码  #最low,淘汰 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 #混口饭吃 def add(ho ...

  4. Kotlin——从无到有系列之中级篇(四):面向对象的特征与类(class)继承详解

    如果您对Kotlin很有兴趣,或者很想学好这门语言,可以关注我的掘金,或者进入我的QQ群大家一起学习.进步. 欢迎各位大佬进群共同研究.探索 QQ群号:497071402 进入正题 在前面的章节中,详 ...

  5. 大数据技术之_16_Scala学习_05_面向对象编程-中级

    第七章 面向对象编程-中级7.1 包7.1.1 Java 中的包7.1.2 Scala 中的包7.1.3 Scala 包的特点概述7.1.4 Scala 包的命名7.1.5 Scala 会自动引入的常 ...

  6. Python中级 —— 01面向对象进阶

    面向对象进阶 总结.补充(http://blog.csdn.net/fgf00/article/details/52479307) 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊方法 反射 ...

  7. 【Java中级】(一)面向对象的特性与八种基本类型

    1.1.Java 基本数据类型: Java提供了8种基本类型.六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型. byte.short.int.long.float.double. ...

  8. 7. Scala面向对象编程(中级部分)

    7.1 包 7.1.1 看一个应用场景 现在有两个程序员共同开发一个项目,程序员xiaoming希望定义一个类取名Dog,程序员xiaohong也想定一个类也叫Dog,两个程序员还为此吵了起来,该怎么 ...

  9. 15、Java中级进阶 面向对象 继承

    1.何为面向对象 其本质是以建立模型体现出来的抽象思维过程和面向对象的方法(百度百科)是一种编程思维,也是一种思考问题的方式 如何建立面向对象的思维呢?1.先整体,再局部2.先抽象,再具体3.能做什么 ...

随机推荐

  1. Kubeadm部署K8S(kubernetes)集群(测试、学习环境)-单主双从

    1. kubernetes介绍 1.1 kubernetes简介 kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理.目的是实现资源管理的自动 ...

  2. Vue.js的指令、生命周期钩子与数据选项

    vue.js官网:https://cn.vuejs.org/v2/guide/components-registration.html 一.常用指令 v-if ... v-else: 作用:控制元素是 ...

  3. C语言system函数

    我们今天来看看在windows操作系统下system () 函数详解(主要是在C语言中的应用) 注意:在windows下的system函数中命令可以不区别大小写! 函数名: system 功 能: 发 ...

  4. iOS中播放音效

    #import "ViewController.h" #import <AVFoundation/AVFoundation.h> @interface ViewCont ...

  5. Linux curl命令进行网络请求

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11841353.html 1. curl get请求: curl http://www.baid ...

  6. Cadence物理库 LEF 文件语法学习【持续更新】

    我是 雪天鱼,一名FPGA爱好者,研究方向是FPGA架构探索. 关注公众号,拉你进"IC设计交流群". @ 目录 一.LEF简介 1.1 通用规则 1.2 管理 LEF 文件 二. ...

  7. Kubernetes 集群和应用监控方案的设计与实践

    目录 Kubernetes 监控 监控对象 Prometheus 指标 实践 节点监控 部署 Prometheus 部署 Kube State Metrics 部署 Grafana 应用如何接入 Pr ...

  8. gpg 使用入门

    1. 生成秘钥 gpg --full-generate-key 等价于 gpg --full-gen-key Real name: yellowconvict为该秘钥的名字,也称为 USER-ID 在 ...

  9. Python支付宝单笔转账接口

    开发信息 接口加签方式为证书模式 证书模式好处是可以使用支付宝的转账到支付宝账户,也就是提现功能,公钥模式不能实现转账到支付宝账户. 此DEMO利用单笔转账到支付宝账户接口[提现功能]用户可以通过此D ...

  10. 02编程语言与python介绍

    编程语言分类 机器语言:直接用计算机能理解的二进制指令去编写程序,是直接在控制计算机硬件 优点:运行效率高 缺点:开发效率低 1.开发一个简单的小功能都要哟个到非常多条数的二进制指令 2.二进制指令非 ...