Practice| 面向对象
实参与形参的传递机制
* 实参给形参赋值:
* 1、基本数据类型:
* 实参给形参的数据值,形参的修改和实参无关
* 2、引用数据类型
* 实参给形参的地址值,如果这个地址值修改“属性”会影响实参,但是你如果修改是地址值,和实参无关了
*/
class MianShiTi{
String str = new String("good idear"); //创建字符串对象;
char[] ch = {'a','b','c','d'}; //创建数组; public static void main(String[] args){
MianShiTi m = new MianShiTi(); //创建一个对象; exchange(m.str, m.ch);
//m.str没有变,m.ch的[1]变了
System.out.println(m.str); //good idear ,它们是两个无关的str
System.out.println(m.ch); //a*cd String s = "bbbb";
StringBuffer b = new StringBuffer("bbbb");
change(s,b);
//s不可变,s仍然"bbbb"
//b的内容就从"bbbb" ---> "aaaa"
System.out.println(s+b); //bbbbaaaa } public static void exchange(String str, char[] ch){ //两个都是引用数据类型String和char[]数组,
str = "Hello World"; //字符串对象是不可变的,一旦修改str=xxx,就是产生新的对象,和原来的"实参"无关
System.out.println(str); //Hello World
ch[1] = '*'; //数组元素是可变的,ch形参和上面的m.ch实参指向的是同一个数组,所以ch[1]修改,就是修改m.ch[1]
System.out.println(ch); //a*cd
} private static void change(String s, StringBuffer b){ //两个形参为String类型和 类 都是引用数据类型
s = "aaa";
b.setLength(0);//b的长度设置为0,相当于清空原来b中内容
b.append("aaaa");//append表示追加,又追加了aaaa
} }
public class MainTest{
public static void test(String str){
str = "hello";
}
public static void main(String[] args){
String str = "beijing";
test(str);
System.out.println(str); //beijing
}
}
public class TestMethod { //i,str,j是形参
public static void change(int i, String str, Integer j, MyData my){
i++;//这里i无论怎么改,和实参无关
str += "尚硅谷";//字符串对象是不可变的,一旦改变,会产生新对象,str中的地址值变了
j++;//Integer对象是不可变的,一旦改变,会产生新对象,j中的地址值变了
//my.num = 20;
my = new MyData();
my.num = 100;
}
public static void main(String[] args){
int a = 10;
String s = "hello";
Integer b = 20;
MyData m = new MyData(); change(a,s,b,m);//a,s,b,m是实参 System.out.println("a = " + a); //a=10
System.out.println("s = " + s); //s=hello
System.out.println("b = " + b); //b=20
System.out.println("m.num = " + m.num); //n.num=100
}
}
class MyData{
int num = 10;
}
class TEXT{
public int num;
public String str; public TEXT(int num, String str){
this.num = num;
this.str = str;
}
}
public class Class4 {
public static void f1(TEXT tIn, int intIn, Integer integerIn, String strIn){
tIn.num =200;
tIn.str = "bcd";
intIn = 200;
integerIn = 200;
strIn = "bcd";
}
public static void main(String[] args) {
TEXT tIn = new TEXT(100, "abc"); //tIn引用数据类型,对象
int intIn = 100;
Integer integerIn = 100;
String strIn = "abc"; f1(tIn,intIn,integerIn,strIn);
//引用数据类型 + 引用数据类型+int+Integer +String
System.out.println(tIn.num + tIn.str + intIn + integerIn + strIn);
} //200 bcd + 100 + 100 + abc
} ===>>>200bcd100100abc
用数组来管理属性、对象等
/*
(1)声明一个日期类型MyDate:有属性:年year,月month,日day
(2)创建2个日期对象,分别赋值为:你的出生日期,你对象的出生日期,放到数组中
(3)遍历显示
*/
public class TestMydate { public static void main(String[] args) {
MyDate[] arr = new MyDate[2]; //创建长度为2的数组 arr[0] = new MyDate(); //引用数据类型需要给它赋值一个对象; arr[0].year = 1994;
arr[0].month = 7;
arr[0].day = 7; arr[1] = new MyDate();
arr[1].year = 1996;
arr[1].month = 7 ;
arr[1].day = 7; for(MyDate num : arr){
System.out.println(num.year + "-" + num.month + "-" + num.day);
}
class TestTeacher{
public static void main(String[] args){ //用数组来管理属性,创建的对象,排序等
Teacher[] arr = new Teacher[5]; //声明一个一维数组,来存储5个Teacher的对象;
arr[0] = new Teacher(); //arr[0]代表一个元素,是Teacher类型(引用数据类型),需要赋值为一个Teacher对象;
arr[0].name = "kris";
arr[0].age = 18;
arr[0].gender = '男';
arr[0].course = "java"; Teacher t2 = new Teacher();
t2.name = "alex";
t2.age = 11;
t2.gender = '女';
t2.course = "Mysql";
arr[1] = t2; for(int i = 0;i < arr.length;i++){
//arr[i]是一个Teacher的对象
//Exception in thread "main" java.lang.NullPointerException空指针异常
//一旦报NullPointerException,说明对象是null
//arr[i]是否是null?
//if(arr[i] != null){
System.out.println(arr[i].name + "\t" + arr[i].age + "\t" + arr[i].gender + "\t" +arr[i].course);
//} } }
} class Teacher{
String name;
int age;
char gender;
String course;
}
练习2
声明一个圆类Circle,有属性半径radius
声明一个测试类TestCircleArray,
在main方法中,创建一个Circle数组,长度为3,并创建三个Circle对象放到数组中,
遍历显示数组,显示每一个圆的半径、面积。
然后在对Circle数组进行排序,按照半径从小到大,再次遍历显示数组,显示每一个圆的半径、面积
*/ class TestCircle2{
public static void main(String[] args){ Circle[] arr = new Circle[3]; //创建一个Circle数组,长度为3,默认值都为null //创建3个Circle对象放到数组中, 动态输入创建
java.util.Scanner input = new java.util.Scanner(System.in);
for(int i = 0; i < arr.length;i++){
arr[i] = new Circle(); //先创建圆Circle的对象
System.out.print("请输入圆的半径:");
arr[i].radius = input.nextDouble();
System.out.println("半径" + arr[i].radius + "\t" + "面积" + Math.PI * arr[i].radius * arr[i].radius);
}
/* //静态输入
arr[0] = new Circle();
arr[1] = new Circle();
arr[2] = new Circle(); arr[0].radius = 2.0;
arr[1].radius = 3.0;
arr[2].radius = 1.0;
*/
//冒泡排序按从小到大顺序排,需要排arr.length-1次,大的就往后
//第一轮:i=1,j=0,1两次
//第二轮:i=2,j=1一次
for(int i = 1; i < arr.length;i++){
for(int j = 0;j < arr.length-i;j++){ //如果前面的圆的半径比较后面的圆的半径大,就交换两个圆
if(arr[j].radius > arr[j+1].radius){ //比较的是圆的半径,对象需要.半径属性
Circle temp = arr[j];//temp的类型和arr[j]和arr[j+1]一样,它俩是Circle
arr[j] = arr[j+1];
arr[j+1] = temp;
}
} } for(int i = 0; i < arr.length;i++){
System.out.println(arr[i].radius);
}
} }
class Circle{
double radius; }
练习3
(1)声明一个丈夫类型Husband,有属性:姓名,年龄,妻子,其中妻子是Wife类型
(2)声明一个妻子类型Wife,有属性:姓名,年龄,丈夫,其中丈夫是Husband类型
(3)创建一个丈夫对象,创建一个妻子对象,并显示他们的信息 */
class Test3{
public static void main(String[] args){ Husband hus = new Husband(); //hus丈夫对象;
hus.name = "kris";
hus.age = 20; Wife wif = new Wife(); //wif妻子对象;
wif.name = "xka";
wif.age = 19; hus.qi = wif; //qi为引用数据类型,必须给它赋值一个对象;
wif.fu = hus; System.out.println("丈夫的信息:"+hus.name + "\t" + hus.age + "\t" + "妻子的信息:" + hus.qi.name + hus.qi.age);
System.out.println("妻子的信息:" + wif.name + "\t" + wif.age + "\t" +"丈夫的信息:"+ wif.fu.name); }
} class Husband{
String name;
int age;
Wife qi; } class Wife{
String name;
int age;
Husband fu; }
/*
2、练习2
(1)声明一个日期类型MyDate,包含年、月、日
(2)声明一个员工类,包含属性:姓名、薪资、生日,其中生日是MyDate类型
(3)声明一个测试类,在main方法中,声明一个数组,创建三个员工对象,并为属性赋值
(4)遍历显示员工信息,并且按照生日排序
(5)遍历显示员工信息,按照薪资排序
*/ class Test2{
public static void main(String[] args){
Staff[] arr = new Staff[3]; //声明一个数组,创建员工对象,并为他们赋值; java.util.Scanner input = new java.util.Scanner(System.in); for(int i = 0; i < arr.length; i++){
arr[i] = new Staff();
System.out.print("请输入员工姓名:");
arr[i].name = input.next();
System.out.print("员工薪资:");
arr[i].salary = input.nextInt();
System.out.println("请输入员工生日");
arr[i].birthday = new MyDate(); //birthday为引用数据类型,必须给它赋值一个对象;
System.out.print("年:");
arr[i].birthday.year = input.nextInt();
System.out.print("月:");
arr[i].birthday.month = input.nextInt();
System.out.print("日:");
arr[i].birthday.day = input.nextInt();
}
System.out.println("姓名\t" + "薪资\t" + "生\t日");
//遍历显示员工信息;foreach循环
//for(元素的数据类型 元素名 : 数组名){}
for(Staff num : arr){
//System.out.println(arr[i].name + "\t" + arr[i].salary + "\t" + arr[i].birthday.year + "-" + arr[i].birthday.month + "-" + arr[i].birthday.day);
System.out.println(num.name + "\t" + num.salary + "\t" + num.birthday.year + "-" + num.birthday.month + "-" + num.birthday.day);
} //冒泡排序;按员工生日排序;从小到大
for (int j = 1;j < arr.length;j++){ for(int i = 0;i < arr.length-i; i++){ if(arr[i].birthday.year > arr[i+1].birthday.year){ //先比较年year,大的年龄小
Staff temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}else if(arr[i].birthday.year == arr[i+1].birthday.year){
if(arr[i].birthday.month > arr[i+1].birthday.month){
Staff temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}else if(arr[i].birthday.month == arr[i+1].birthday.month){
if(arr[i].birthday.day > arr[i+1].birthday.day){
Staff temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
}
}
//遍历排序之后的
System.out.println("排序之后的:");
System.out.println("姓名\t" + "薪资\t" + "生\t日");
for(int i = 0;i < arr.length; i++){ System.out.println(arr[i].name + "\t" + arr[i].salary + "\t" + arr[i].birthday.year + "-" + arr[i].birthday.month + "-" + arr[i].birthday.day);
}
} }
class MyDate{
int year;
int month;
int day; }
class Staff{
String name;
double salary;
MyDate birthday; }
类的继承,super 1、写一个名为Account的类模拟账户。该类的属性和方法如下图所示。该类包括的属性:账号id,余额balance,年利率annualInterestRate;
包含的方法:访问器方法(getter和setter方法),返回月利率的方法getMonthlyInterest(),取款方法withdraw(),存款方法deposit()。
写一个测试类TestAccount:在用户程序中,创建一个账号为11223344、余额为20000、年利率4.5%的Account对象。使用withdraw方法提款30000元,并打印余额。
再使用withdraw方法提款2500元,使用deposit方法存款3000元,然后打印余额和月利率。 2、创建Account类的一个子类CheckAccount代表可透支的账户,该账户中定义一个属性overdraft代表可透支限额,。在CheckAccount类中重写withdraw方法。
写一个用户程序测试CheckAccount类。在用户程序中,创建一个账号为11223344、余额为20000、年利率4.5%,可透支限额为5000元的CheckAccount对象。 提示:
(1)子类CheckAccount的构造方法需要将从父类继承的3个属性和子类自己的属性全部初始化。
(2)父类Account的属性balance被设置为private,但在子类CheckAccount的withdraw方法中需要修改它的值
最后思考:如果将父类Account的属性balance设置为protected,会怎么样?
package com.atguigu.variable; import com.atguigu.inherited.Account; public class CheckAccount extends Account { private double overdraft; public CheckAccount() {
super();
} public CheckAccount(String id, double balance, double annualInterestRate, double overdraft) {
super(id, balance, annualInterestRate);
this.overdraft = overdraft;
} public double getOverdraft() {
return overdraft;
} public void setOverdraft(double overdraft) {
this.overdraft = overdraft;
} /* public void withdraw(double money){
if(money < 0){
System.out.println("输入有误");
}if(money < getBalance()){
super.withdraw(money); //正常取,可以使用父类里边的方法withdraw
}else{ //可以透支
if(money > getBalance() + overdraft){
System.out.println("超过可透支额度");
}else{
System.out.println("剩余可透支额度为:" + (overdraft -= money - getBalance())); //取后剩余的透支额度;
//超过的额度(money - balance);
setBalance(0);
System.out.println("哎呀取完了,账户余额为:" + getBalance());
} }
}*/ // 如果将父类Account的属性balance设置为protected,表在其他包的子类里边也可以使用
public void withdraw(double money){
if(money < 0){
System.out.println("您的输入有误");
}if(money < balance){
super.withdraw(money);
}else{
if(money > balance + overdraft){
System.out.println("超过卡的取款额度");
}else{
System.out.println("可透支额度剩余:" + (overdraft -= money -balance));
setBalance(0);
}
}
} }
package com.atguigu.variable; import com.atguigu.inherited.Account; public class TestAccount { public static void main(String[] args) {
// TODO Auto-generated method stub
Account a = new Account("11223344", 20000, 0.045);
CheckAccount c = new CheckAccount("11223344", 20000, 0.056, 5000); c.withdraw(28000);//传参调用withdraw方法,它是没有返回值的。
//System.out.println(a.getBalance());
System.out.println(a.deposit(2000)); } }
多态转型
// A(show(D obj) show(A obj)) --> B(show(B obj) show(A obj) ) --> C
// --> D
//父类的变量可以存储子类的对象;但子类的变量不能存储父类的对象; D13Exam
public class Exam1 {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B(); //向上转型 a2对象可以调用B中重写父类的方法show(A obj)(重写的形参看是否符合 父类的引用变量接收子类的对象。) 和 父类中的方法。
B b = new B(); //本态引用,b可以调用它自己即子类B中的方法和继承父类的方法,只要参数符合就可以。
C c = new C();
D d = new D();
System.out.println("(1)" + a1.show(b));//调用A类中的哪个show方法,实参是子类B的对象b,b可以传给它的父类引用变量 A obj 多态参数
System.out.println("(2)" + a2.show(b));//B类的对象有几个show方法? D继承了B,B继承了A;
//((1)show(D obj)(2)show(A obj)(3)show(B obj)),这里传的实参类型D类型d对象,选择show(D obj)执行
System.out.println("(3)" + b.show(c));//b类的对象有几个方法? b可以调用B和A中所有的方法,形参c 可以传给它的父类;多态参数。
// 这里传的实参类型是C类型的c对象,如果有形参C类型的,肯定首选,这里没有,看哪个合适,选择B类型
System.out.println("(4)" + b.show(d));
// 这里传的实参类型是D类型的d对象,有合适的, }
}
class A{
public String show(D obj){
return ("A and D");
}
public String show(A obj){ //a1对象可以调用哪个传入B类型的show方法呢?B继承了A
return "A and A";
}
}
class B extends A{
public String show(B obj){
return "B and B";
}
@Override
public String show(A obj){ //重写了父类show(A obj)的方法
return "B and A";
}
}
class C extends B{ }
class D extends B{ ---》》
(1)A and A
(2)B and A
(3)B and B
(4)A and D
多态针对方法的,属性没有多态,注意权限修饰符
public class Exam2 {
public static void main(String[] args) {
Base b = new Sub();//多态引用
System.out.println(b.x);//属性没有多态,按照编译时,b对象有1个x,是Base类中 //
}
}
class Base{
int x = 1;
}
class Sub extends Base{
int x = 2;
}
public class Child extends Father{
public String grade; public static void main(String[] args){
Father f = new Child(); //向上转型;
System.out.println(f.name);//因为name是private的,所以编译错误;
}
} class Father{
private String name = "atguigu"; //private 只能在本类中使用。
int age = 0;
}
this、继承时构造器的调用
public class Teacher extends Person{
private String name = "tom";
public Teacher(){
System.out.println("this is a teacher.");
// super(); //编译错误,必须在子类构造器的首行
}
public static void main(String[] args){
Teacher tea = new Teacher();
// System.out.println(this.name);//编译错误,this不能在static方法中使用的
}
}
class Person{
public Person(){
System.out.println("this is a Person.");
}
}
继承、构造器、super、方法的重写、多态引用
public class Test { public static void main(String[] args) {
Base b1 = new Base();//本态引用,只看Base类,执行了Base类的无参构造,在无参构造中,调用了Base类的method(100)
Base b2 = new Sub(); //执行的是子类重写的方法。
//多态引用,创建的是子类的对象,执行子类Sub的无参构造;
//在子类的构造器中,一定会调用父类的构造器,默认调用的是父类的无参构造,会导致父类的无参构造被执行,因为父类的无参构造中调用method(100),
//它省略了“this.”,这个this是当前对象,当前正在创建的是子类Sub的对象,执行的是子类Sub重写的method(100)
//接着在子类的构造器中,有super.method(70),这个执行的是父类的method(70),所以会打印 Base:70 }
}
class Base{
Base(){
method(100); //省略了this.method(100),this指当前对象
}
public void method(int i){
System.out.println("base : " + i); // 1.base: 100; 3. base: 70
}
}
class Sub extends Base{
Sub(){
//省略了super();
super.method(70); //super.方法。子类重写了method方法,但是它又想调用父类的method方法了。
}
public void method(int j){ //子类重写了method方法。
System.out.println("sub : " + j); //2. sub: 100 ;
}
} --->>
base : 100
sub : 100
base : 70
类初始化和实例初始化
如果没有实例化(例如main方法中执行了某个函数),没有创建对象,只执行类的实例化,不进行实例的初始化。
public class Test {
{
System.out.println("b");
}
static{
System.out.println("a");
}
Test(){
System.out.println("c");
}
public static String getOut(){
try {
return "1";
} catch (Exception e) {
return "2";
}finally{
return "3";
}
}
public static void main(String[] args) {
System.out.println(getOut());
}
} ===》》 a 3
* 类初始化和实例初始化
* (1)先类初始化
* A:如果父类没有初始化,会先初始化父类
* B:类的初始化执行的是<clinit>方法,它由两部分组成:
* (a)静态变量的显式赋值语句 (b)静态代码块的语句,(a)(b)谁在上谁先执行
*
* (2)实例初始化
* A:创建子类对象时,也会导致父类的实例初始化方法执行
* B:每一个构造器都会有对应的实例初始化方法
* C:每一个实例初始化有三部分组成:
* (a)非静态变量的显示初始化代码(b)非静态代码块的语句(c)构造器; (a)(b)谁在上谁先执行,构造器后执行
子类继承父类,子类和父类都有无参构造和有参构造;子类在进行创建对象时,不管子类创建对象时候它有没有传参,
子类都是默认调用父类的无参构造,如果传参了,那么参数传给的是子类的有参构造。
练习:
/*
* 实例初始化的过程:
* 1、父类的实例初始化<init>()
* 因为子类默认调用父类的无参构造,那么选择父类的<init>(),而不是<init>(String name)
* System.out.print("1");
* 2、子类的实例初始化
* System.out.print("3");
* father = new People(name +" F"); //创建了父类的对象
* 这句代码会导致,父类的有参构造,即父类的<init>(String name)会执行
* System.out.print("2");
*
*/
public class TestChild {
public static void main(String[] args) {
new Child("mike");//
}
}
class People{
private String name;
public People(){
System.out.print("1");
} public People(String name){
System.out.print("2");
this.name = name;
System.out.println(name);
}
}
class Child extends People{
People father; //子类的构造器中,默认会调用父类的无参构造
public Child(String name){
System.out.print("3");
father = new People(name +" F"); } public Child(){
System.out.print("4");
} } 打印:--->>
132mike F
父类初始化< clinit >---->>>子类初始化< clinit >--->> 父类的实例初始化< init > --->>子类的实例初始化< init >;一开始都是静态的先初始化。
(1.先父类初始化;2.子类初始化; 3.父类实例初始化; 4.子类实例初始化。)
练习:
* 1、实例初始化,为属性赋值的过程
* (1)父类的实例初始化方法<init>()
* x = 10;//父类中的x
* this.print();//要考虑方法的重写,因为在创建子类Son的对象,所以这个this是子类的对象
* System.out.println("Son.x = " + x);// Son.x = 0 ,这个是子类中的x
* x = 20;//父类中的x
* (2)子类的实例初始化方法<init>()
* x = 30;//子类的x
* this.print();
* System.out.println("Son.x = " + x);//子类中的x,就近原则 Son.x = 30
x = 40;//子类的x
*
* 2、属性没有多态
* System.out.println(f.x);//按照编译时类型,父类的x
*/
public class Exam3 {
public static void main(String[] args) {
Father f = new Son();
System.out.println(f.x);//先初始化最后执行这个,按照编译时类型,父类的x;属性没有多态。
}
}
class Father{
int x = 10; //父类的实例初始化; 显式赋值;
public Father(){ //构造器;
this.print();//this指的是当前对象,即Son对象,它重写了print方法,所以调用的是子类的print方法
x = 20;
}
public void print(){
System.out.println("Father.x = " + x);
}
}
class Son extends Father{
int x = 30;
public Son(){
this.print();
x = 40;
}
public void print(){ //执行这个方法的时候x还没赋值,它的默认值为0
System.out.println("Son.x = " + x);//子类中的x,就近原则
}
} ----->>> 打印:
Son.x = 0
Son.x = 30
20
* 实例初始化的问题:
* 1、创建父类对象时
* 执行父类的实例初始化方法<init>
* System.out.println("father create");
* 2、创建子类对象时
* 执行父类的实例初始化方法<init>
* System.out.println("father create");
* 执行子类的实例初始化方法<init>
* System.out.println("child create");
*/
public class Child extends Father{
public Child(){
System.out.println("child create");
} public static void main(String[] args) {
Father f = new Father(); //先执行这一句,父类 f 的实例初始化
Child c = new Child(); //再执行子类的实例初始化 --> 它会导致父类的先初始化再初始化子类
}
} public class Father {
public Father(){
System.out.println("father create");
}
} 打印:
father create
father create
child create
* 1、创建对象
* 实例初始化
* (1)父类的实例初始化<init>
* name = "father"; //这个name是父类的name
* (2)子类的实例初始化<init>
* name = "test"; //这个name是子类的name
*
* 2、对象调用方法
* 调用的是子类从父类继承的getName()
*
* 子类的对象有两个name, this.name,如果在子类中,this.name就是子类的,如果在父类中,this.name就是父类的
*/
public class Test extends Father{
private String name = "test"; public static void main(String[] args) {
Test test = new Test();
System.out.println(test.getName());
}
} public class Father {
private String name = "father"; public String getName() {
return name;//这里就近原则,找的是父类的name
}
}
* 1、创建对象
* Other o = new Other(); o.i = 0;
* 2、调用了addOne(o)
* o.i++; o.i = 1;
* 3、final修饰的变量不可变问题
* 是修饰什么变量,局部变量还是成员变量?
*/
public class Something {
public static void main(String[] args) {
Other o = new Other();
new Something().addOne(o); //对象.方法
System.out.println(o.i);
}
//final修饰的变量不可变; 这里是o变量不可变
public void addOne(final Other o){
// o = new Other();//o的变量值不可变
o.i++;
}
}
class Other{
public int i;
}
* 1、static
* 本类中,静态的方法,代码块可以访问静态的属性
* 2、类初始化
* main方法所在的类必须先初始化,然后才能执行main方法
*
* Myclass2类的初始化<clinit>()
* static{
int x = 5;
x--;//这里的x是局部变量的x,不是类变量的x x = 4
}
static{
x--;//这里的x是类变量的x x = -1
}
* 在执行main
* System.out.println("x = " + x);//类变量的x x=-1
z--;//类变量的z z= -1
myMethod();
y = z++ + ++z;//都是类变量
(1)先把z=-1的值load到操作数栈(2)z++,z=0(3)++z,z=1(4)再把z=1的值load到操作数栈(5)计算-1+1(6)赋值给y=0
System.out.println("result: " + (z + y + ++z));
(1)先把z=1的值load到操作数栈(2)再把y=0的值load到操作数栈
(3)++z,z=2(4)先把z=2的值load到操作数栈(5)执行1+0+2(6)打印3
* 2、局部变量与成员变量(类变量、实例变量)
* 3、自增问题
*
*/
public class Myclass2 {
static int x,y,z;
static{
int x = 5; //局部变量
x--;
}
static{
x--; //这里的x是类变量
}
public static void main(String[] args) {
System.out.println("x = " + x);//类变量的x x=-1
z--;//类变量的z z= -1
myMethod();
System.out.println("result: " + (z + y + ++z));
} public static void myMethod(){
y = z++ + ++z;
}
} x = -1
result: 3
==和equals()的区别 ==:如果是基本数据类型,比较的是数据值
如果是引用数据类型,比较的是对象的地址值
equals():必须是对象才能调用,它是Object类中声明的,如果子类没有重写,那么它的效果和==是一样的,也是比较对象的地址。如果子类重写了,
那么就按照重写的规则进行比较,例如String类型重写了equals,比较的是字符串的字符内容。
重写一个类的equals方法需要主意什么?
(1)必须和hashCode()方法一起重写,凡是参与equals比较的属性,一定要参与hashCode值的计算。
(2)equals的重写要求遵循几个原则:
equals 方法在非空对象引用上实现相等关系:
• 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
• 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
• 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
• 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
• 对于任何非空引用值 x,x.equals(null) 都应返回 false。
Practice| 面向对象的更多相关文章
- 汉企C#面向对象——继承Practice
class Dianqi //创建电器类:父类 { private string _Dianqimingzi; public string Dianqimingzi { get { return _D ...
- 一起学 Java(二)面向对象
一.方法函数 函数也称为方法,就是定义在类中的具有特定功能的一段独立代码.用于定义功能,提高代码的复用性. 函数的特点1> 定义函数可以将功能代码进行封装,便于对该功能进行复用:2> 函数 ...
- python 面向对象初级篇
Python 面向对象(初级篇) 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发" ...
- python面向对象初级(七)
概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向过程编程最易被初学 ...
- Python 面向对象(初级篇)
51CTO同步发布地址:http://3060674.blog.51cto.com/3050674/1689163 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后 ...
- 面向对象day1
一.什么是面向对象 之前我们学习过面向过程和函数式编程,在讲函数的时候有说过之所以有函数式编程是因为面向过程编程是根据业务逻辑从上到下垒代码,会出现大量代码的重用和臃肿,so,函数式编程将同一功能的代 ...
- Python 面向对象(初级篇) (转)
概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发"更快更好更强..." 面 ...
- day6-2面向对象
概述: 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 注:Java和C#来 ...
- Python全栈--9 __import__ 反射和面向对象基础 self 封装 继承(多继承的顺序) 多态
一.反射 python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员.获取成员.设置成员.删 ...
随机推荐
- Python-爬虫-租房Ziroom
目标站点需求分析 涉及的库 import requestsimport timeimport pymongofrom lxml import etreefrom requests.exceptions ...
- es6 super关键字
rhttp://es6.ruanyifeng.com/#docs/class-extends super关键字,既可以当作函数使用,也可以当作对象使用.这俩种的使用是不一样的 第一种:函数使用 代表父 ...
- Sybase·调用存储过程并返回结果
最近项目要用Sybase数据库实现分页,第一次使用Sybase数据库,也是第一次使用他的存储过程.2个多小时才调用成功,在此记录: 项目架构:SSM 1.Sybase本身不支持分页操作,需要写存储过程 ...
- 在启用属性的情况下启动 Confluence 6
在一些情况下,你可以希望 Confluence 在系统启动的时候就对属性文件进行打印.如果你的 Confluence 经常进行重启,并且你可能忘记来启动针对系统诊断的属性文件日志开关. 编辑 CONF ...
- 为 Confluence 6 配置发送邮件消息
如何配置 Confluence 向外发送邮件: 进入 > 基本配置(General Configuration) > 邮件服务器(Mail Servers).这里列出了所有当前配置的 S ...
- Confluence 6 MBeans
你可以使用下面的 Confluence MBeans 来实时查看你 Confluence 实例运行的实时信息. CacheStatistics 这个 MBean 显示了 Confluence 有关的 ...
- nginx+php负载均衡集群环境中的session共享方案梳理
在网站使用nginx+php做负载均衡情况下,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态. 下面罗列几种nginx负载均衡 ...
- Cookie禁用了,Session还能用吗?原因详解
Cookie与 Session,一般认为是两个独立的东西,Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案.但为什么禁用Cookie就不能得到Session ...
- IO伪异步实现
伪异步的实现,通过多线程,也会阻塞,等待连接 1.创建TcpServer类 package com.cppdy.tcp; import java.io.IOException; import java ...
- github文档
Video Guides GitHub Help GitHub.com Hello World 10 minute read Intro What is GitHub? Create a Repo ...