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. 前缀函数与Z函数介绍

    字符串算法果然玄学=_= 参考资料: OI Wiki:前缀函数与KMP算法 OI Wiki:Z函数(扩展KMP) 0. 约定 字符串的下标从 \(0\) 开始.\(|s|\) 表示字符串 \(s\) ...

  2. python 小兵(3)字典

    字典 # 存储数据 字典的查找快一些# 不可哈希的,就是可变的数据 可变的数据不能哈希 不可变的数据能哈希# python3.6 版本以上 字典默认是有序的, 咱们怎么写的就怎么打印出来# 但是 出去 ...

  3. 洛谷P4859 已经没有什么好害怕的了

    因为不存在任意两个数相同,那么设糖果比药片大的组有 \(x\) 个,药片比糖果大的组有 \(y\) 个,那么我们有: \[x + y = n, x - y = k \] 即: \[x = \frac{ ...

  4. 解决 413 Request Entity Too Large

    修改配置文件  vim /etc/nginx/sites-available/default,增加 client_max_body_size 1000m;//最大上传大小 proxy_connect_ ...

  5. UIView的常见方法

    - (void)addSubview:(UIView *)view; 添加一个子控件view - (void)removeFromSuperview; 将自己从父控件中移除 - (UIView *)v ...

  6. 通过bindservice方式调用服务方法里面的过程

    为什么要引入bindService:目的为了调用服务里面的方法 (1)定义一个服务 服务里面有一个方法需要Activity调用 (2)定义一个中间人对象(IBinder) 继承Binder (3)在o ...

  7. centos安装Libzip

    2018年06月29日 11:12:15 oxiaobaio 阅读数 4827   wget https://nih.at/libzip/libzip-1.2.0.tar.gztar -zxvf li ...

  8. 1Appium Desktop 的简单应用

    由于Appium Desktop出来了,所以使用appium要比以前简单许多,现在根据以前的文章针对Appium Desktop做下修改更新 之前文章链接:https://testerhome.com ...

  9. 虫师Selenium2+Python_11、自动化测试项目实战

    P276 11.1.3 自动化测试用例编写原则 在编写自动化测试用例过程中应该遵循以下原则: 1.一个用例为一个完整的场景,从用户登录系统到最终退出并关闭浏览器: 2.一个用例只能验证一个功能点,不要 ...

  10. 【Azure 应用服务】应用代码需要客户端证书进行验证,部署到App Service后,如何配置让客户端携带证书呢?

    问题描述 .NET 6 MVC应用,代码中要求客户端访问时候必须携带正确的证书,如果不携带或者携带错误的证书,都会得到 HTTP ERROR 403 Forbidden 错误 在App Service ...