面向对象(三)
一、关于变量赋值
如果变量是基本数据类型,此时赋值的是变量所保存的数据值
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值
public class ValueTransferTest {
public static void main(String[] args) {
int m = 10;
int n = m;
System.out.println("m="+m+",n="+n);
n = 20;
System.out.println("m="+m+",n="+n);
System.out.println("*************************引用数据类型");
Order o1= new Order();
o1.orderId = 1001;
Order o2 = o1;//赋值后两个地址值相同
System.out.println("o1.orderId="+o1.orderId+",o2.orderId"+o2.orderId);
o2.orderId = 1002;
System.out.println("o1.orderId="+o1.orderId+",o2.orderId"+o2.orderId);
}
}
class Order{
int orderId;
}
二、方法的形参传递机制,值传递
1.形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
2.值传递机制
如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
public class ValueTransferTest1 {
public static void main(String[] args) {
int m = 10;
int n = 20;
System.out.println("m="+m+",n="+n);
//交换两个变量的值操作
// int temp = m;
// m = n;
// n = temp;
ValueTransferTest1 test1 = new ValueTransferTest1();
test1.swap(m, n);
System.out.println("m="+m+",n="+n);
}
public void swap(int m, int n) {
int temp = m;
m = n;
n = temp;
}
}
三、面向对象特征一:封装与隐藏
- 一、问题引入
- 当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里,赋值操作要受到
- 属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值
- 加入额外的限制条件。这个属性不能在声明时体现,我们只能通过方法进行限制条件的添加。
- 同时,我们需要避免用户再使用“对象.属性”的方式对属性进行赋值,则需要将属性声明为私有的(private)
—>此时,针对于属性就体现了封装性。
二、封装性的体现
我们将类属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)属性
拓展:封装性的体现:①如上②不对外暴露的私有方法③单例模式
三、封装性的体现,需要权限修饰符来配合。
1.java规定4种权限:从小到大:private、缺省、protected、public
2.4种权限可以用来修饰类和内部结构:属性、方法、构造器、内部类
3.具体的,4种权限可以用来修饰类和内部结构:属性、方法、构造器、内部类
修饰类的话,只能使用:缺省、public
总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。
public class AnimalTset {
public static void main(String[] args) {
Animal animal = new Animal();
animal.name="大黄";
// animal.age = 1;
// animal.legs=4;
animal.show();
animal.setLegs(-6);
animal.show();
}
}
class Animal{
String name;
private int age;
private int legs;
//对属性的设置
public void setLegs(int l) {
if(l>=0&&l%2==0) {
legs = l;
}else {
legs=0;
}
}
//对属性的获取
public int getLegs() {
return legs;
}
public void eat() {
System.out.println("动物进食");
}
public void show() {
System.out.println("name="+name+",age="+age+",legs"+legs);
}
//提供关于age的get和set方法
public int getAge() {
return age;
}
public void setAge(int a) {
age = a;
}
}
四、面向对象的特征之二:继承性
一、继承性的好处
1)减少了代码的冗余,提高了代码的复用性
2)便于功能扩展
3)为之后多态的使用,提供了前提
*
二、继续性:class A extends B{}
A:子类、派生类 、subclass
B:父类、超类、基类、superclass
2.1体现:一旦子类A继承父类B以后,子类A中就获取了父类B中的声明结构:属性、方法
特别的,父类中声明为private的属性和方法,子类继承父类以后仍然认为获取了父类中私有的结构。
只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
2.2子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。
子类和父类的关系,不同于子类和集合的关系
三、java中关于继续性的规定
1.一个类可以被多个子类继承
2.java中类单继承,一个类只能有一个父类
3.子父类是相对的概念
4.子类直接继承的父类,称为,直接父类。间接继承的父类称为,间接父类。
5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
四、
1.如果我们没有显式的声明一个类的父类的话,则此类继承与java.lang.Object类
2.所有java类(除java.lang.Object类之外)都直接和间接的继承与java.lang.Object类
3.意味着,所有java类都具有java.lang.Object类声明的功能
ExtendsTest 类
public class ExtendsTest {
public static void main(String[] args) {
Person p1 = new Person();
// p1.age=1;
p1.eat();
Student s1 = new Student();
s1.eat();
s1.sleep();
s1.setAge(10);
System.out.println(s1.getAge());
s1.breath();
Creature c = new Creature();
}
}
Creature 类
public class Creature {
public void breath() {
System.out.println("呼吸");
}
}
Person 类
public class Person extends Creature{
String name;
private int age;
public Person() {
}
public Person(String name,int age) {
this.name= name;
this.age = age;
}
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student 类
public class Student extends Person{
// String name;
// int age;
String major;
public Student() {
}
public Student(String name,int age,String major) {
this.name = name;
// this.age = age;
setAge(age);
this.major = major;
}
// public void eat() {
// System.out.println("吃饭");
// }
//
// public void sleep() {
// System.out.println("睡觉");
// }
public void study() {
System.out.println("学习");
}
public void show() {
System.out.println("name="+name+",age="+getAge());
}
}
方法重写(override/ overwrite)
1.重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
2.应用:重写以后,当创建子类对象以后 ,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写 父类的方法
3.重写的规定
方法的声明:权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
方法体
}
约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法
1)子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参相同
2)子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
特殊情况,子类不能重写父类中private权限的方法
3)返回值类型:
父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
父类被重写的方法的返回值类型是A,则子类重写的方法的返回值类型可以是A类或A类的子类
父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据量类型(必须也是double)
4)子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理的时候讲)
子类和父类同名同参数的方法要么都声明为非static(考虑重写),要么都声明为static的(不是重写)
PersonTest 类
public class PersonTest {
public static void main(String[] args) {
Student s = new Student("计算机科学与技术");
s.eat();
s.walk(10);
s.study();
//s.show();
System.out.println("*********");
Person p1 = new Person();
p1.eat();
}
}
Person 类
public class Person {
String name;
int age;
public Person() {
}
public Person(String name,int age) {
this.age = age;
this.name = name;
}
public void eat() {
System.out.println("吃饭");
}
public void walk(int distance) {
System.out.println("走路,走的距离是:"+distance+"公里");
show();
eat();
}
private void show() {
System.out.println("我是一个人");
}
public Object info() {
return null;
}
public double info1() {
return 1.0;
}
}
Student 类
public class Student extends Person{
String major;
public Student() {
}
public Student(String major) {
this.major = major;
}
public void study() {
System.out.println("学习。专业是:"+major);
}
//重写方法
public void eat() {
System.out.println("学生应该多吃有营养的事物");
}
public void show() {
System.out.println("重写");
}
public String info() {
return null;
}
// public int info1() {
// return 1;
// }
public void walk(int distance) {
System.out.println("重写的方法");
}
}
五、面向对象之三:多态性
1.理解多态性,可以理解为一个事物的多种形态
2.何为多态性
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类引用)
3多态的使用,虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法
总结:编译看左边,运行看右边
4.多态性的使用前提:1)类的继承关系 2)方法的重写
5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
Man man = new Man();
man.eat();
man.age=25;
man.earnMoney();
//***************************
System.out.println("**************************");
//对象的多态性:父类的引用指向子类的对象
Person p2 = new Man();
// Person p3 = new Woman();
//多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法---虚拟方法调用
p2.eat();
p2.walk();
// p2.earnMoney();
System.out.println(p2.id);
System.out.println("**************************");
//不能调用子类所特有的方法、属性
// p2.earnMoney();
p2.name = "tom";
// p2.isSmoking = true;
//有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类,导致
//编译时,只能调用父类中声明的属性和方法。子类特有的方法和属性不能调用。
//如何才能调用子类特有的属性和方法
//向下转型,使用强制类型转换符
Man m1 = (Man)p2;
m1.earnMoney();
m1.isSmoking=true;
//使用强转时,可能出现ClassCastException的异常
// Woman w1 = (Woman) p2;
// w1.goShopping();
/*
* instanceof关键字的使用
* a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是返回false;
*
* 使用情景:为了避免在向下转型是出现ClassCaseException的异常,我们在向下转型之前,先
* 进行instanceof的判断,一旦返回true,就进行向下转型。如果返回flase,不能进行向下转型
*
* 如果 a instanceof A返回true,则 a instanceof B也返回true
* 其中,类B是类A的父类
*/
if(p2 instanceof Woman) {
Woman w1 = (Woman) p2;
w1.goShopping();
System.out.println("****Woman***");
}
if(p2 instanceof Man) {
Man m2 = (Man) p2;
m2.earnMoney();
System.out.println("****Man***");
}
if(p2 instanceof Person) {
System.out.println("****Person***");
}
if(p2 instanceof Object) {
System.out.println("****Object***");
}
}
一、回顾 == 的使用
==:运算符
1.可以使用在基本数据类型和引用数据类型变量中
2.如果比较的是基本数据类型变量,比较两个变量保存的数据是否相同。(不一定类型要相同)
如果比较的是引用数据类型变量,比较两个对象的地址值是否相同,即两个引用是否向同一个对象实体
补充 == 符号使用时,必须保证符号左右两边的变量类型一致
二、equals()方法使用
1.是一个方法,而非运算符
2.只能适用于引用数据类型
3.Object类中equals()的定义:
- public boolean equals(Object obj) {
return (this == obj);
} - 说明:Object类中定义的equals()和==的作用相同的:比较两个对象的地址值是否相同,即两个引用是否向同一个对象实体
4.像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是
两个引用的地址是否相同,而是比较两个对象的实体内容是否相同。
5.通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们
就需要对Object类中的equals()进行重写
重写的原则,比较两个对象的实体内容是否相同。
public class EqualsTest {
public static void main(String[] args) {
int i =10;
int j =10;
double d = 10.0;
System.out.println(i==j);
System.out.println(i==d);
boolean b = true;
char c = 10;
System.out.println(i==c);
char c1 = 'A';
char c2 = 65;
System.out.println(c1==c2);
System.out.println("*******************");
Customer cust1 = new Customer("tom",21);
Customer cust2 = new Customer("tom",21);
System.out.println(cust1==cust2);
String str1 = new String("asd");
String str2 = new String("asd");
System.out.println(str1 == str2);
System.out.println("*******************");
System.out.println(cust1.equals(cust2));
System.out.println(str1.equals(str2));
Date date1 = new Date(3214125L);
Date date2 = new Date(3214125L);
System.out.println(date1.equals(date2));
}
}
六、 java.lang.Object
1.Object 类所有java类的根父类
2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Objectl类
3.Object类中的功能(属性、方法)就具有通用性。
属性:无
方法:equals()/toString()/getClass()/hashCode/clone()/finalize()
wait()/notify()/notifyAll()
4.Object类只声明一个空参的构造器
public class ObjectTest {
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.getClass().getSuperclass());
}
}
class Order{
}
课后练习一
已知有一个数列f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n)
其中n是大于0的整数,f(10)的值
public int f(int n) {
if(n==0) {
return 1;
}else if(n==1) {
return 4;
}else {
//return f(n+2)-2*f(n+1);
return 2*f(n-1)+f(n-2);
}
}
课后练习二(存钱取钱)
Account 类
public class Account {
private int id;//账号
private double balance;//余额
private double annualInterestRate;//年利率
public Account(int id,double balance,double annualInterestRate) {
this.id = id;
this.balance = balance;
this.annualInterestRate = annualInterestRate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnualInterestRate() {
return annualInterestRate;
}
public void setAnnualInterestRate(double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
//取钱
public void withdraw(double amount) {
if(balance < amount) {
System.out.println("余额不足,取款失败!");
return;
}
balance -= amount;
System.out.println("成功取出:"+amount);
}
//存钱
public void deposit(double amount) {
if(amount>0) {
balance += amount;
System.out.println("成功存入:"+amount);
}
}
}
Customer 类
public class Customer {
private String firstName;
private String lastName;
private Account account;
public Customer(String f,String l) {
this.firstName = f;
this.lastName = l;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
测试类
public class CustomerTest {
public static void main(String[] args) {
Customer cust= new Customer("Jane", "Smith");
Account acct = new Account(1000, 2000, 0.0123);
cust.setAccount(acct);
cust.getAccount().deposit(100);
cust.getAccount().withdraw(960);
cust.getAccount().withdraw(2000);
System.out.println("Customer["+cust.getLastName()+","+cust.getFirstName()+
"] has a account: id is"+cust.getAccount().getId()+",annualInterestRate is"+
cust.getAccount().getAnnualInterestRate()*100+"% ,balance is"+cust.getAccount().getBalance());
}
}
课后练习三:四种访问权限的修饰符
面试题:重载和重写的区别
1)两者的概念:重写子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。
2)重载
两同一不同,
重写
1)子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参相同
2)子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
特殊情况,子类不能重写父类中private权限的方法
3)返回值类型:
父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
父类被重写的方法的返回值类型是A,则子类重写的方法的返回值类型可以是A类或A类的子类
父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据量类型(必须也是double)
4)子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
5)重载:不表现为多态性
重写:表现为多态性
面试题: == 和equals()区别
==:判断两个字符串在内存中首地址是否相同,即判断两者是否是同一个字符串对象
equles():如果没有重写equals()方法比较的是对象的地址,因为对Object来说对象没有什么属性可以比较,只能比较最底层的地址.
而如果重写equals()方法时,该方法的对象因为是Object的子类,所以调用时会调用子类对象里面的方法.所以只有重写equals()方法后,两者比较的才是内容.或者说重写可以使自己定义比较的规则,不想按照地址去比较.
面试题final、finally、finalize的区别
转载:https://blog.csdn.net/weixin_43811057/article/details/107675224