J2SE第三章——面向对象(二)

5.this

 

this变量的使用:

                  1.用在成员变量前面 (当前对象的sex属性)

                  2.成员方法前 (当前的对象)

                  3.代码冗余:使用this可以调用自身的另外一个构造函数

                  4.this作为返回值

public class Person {

         private int id;

         private String name;

         private boolean sex;

 

         public Person() {

 

         }

 

         public Person(boolean s) {

                   sex = s;

         }

 

         public Person(boolean s,String n) {

                   sex = s;

                   name = n;        

         }

 

         main() {

                   Person p1 = new Person();

         }

}

 

 

public class Person {

         private int id;

         private String name;

         private boolean sex;

         private itn tel;

 

         public Person() {

 

         }

 

         public Person(int id,String name, boolean sex) {

                   this.id = id;

                   this.name = name;

                   this.sex = sex;

 

                   //Person(sex,name);

                   this(sex,name)

                   构造函数内部,如果要访问另外一个构造函数,使用this关键字

 

                   this.eat();

                   就近原则  JVM认为这两个sex都是形参

                   这时 就有必要区分作为形参的sex 和 当前对象的sex属性

                   创建对象,对象内部除了包含有所属类中定义的成员变量外,还包含一个变量

                            命名为this ,this 的值是当前对象的地址

                   换句话说,this就是指向该对象本身

 

                   this变量的使用:

                            1.用在成员变量前面 (当前对象的sex属性)

                            2.成员方法前 (当前的对象)

                            3.代码冗余:使用this可以调用自身的另外一个构造函数

                            4.this作为返回值

 

         }

 

         public Person(boolean sex,String name) {

                   this.sex = sex;

                   this. = name;  

         }

 

         public void eat() {

 

         }

 

         main() {

                   Person p1 = new Person();

         }

}

 

public class Leaf {

         int i = 0;

         Leaf(int i ) {

                   this.i = i;

         }

 

         //方法的返回值类型:返回值的数据类型

         //现在返回的是某个对象的“地址” 那么返回值类型?

         //通过返回值得到的地址,就能找到对应的“对象”

         //所以返回值的类型,就应该是地址标记的对象所属的类型

         Lesf increment() {

                   i++;  //i属于调用该方法的对象leaf

                   return this;  //返回的是this的值,也就是当前对象的地址

         }

 

         void print() {

                   System.out.println("i = " + i);

         }

 

         public static void main(String[] args) {

                   Lesf leaf = new Leaf(100);

                   Leaf l1 = leaf.increment();

                   Leaf l2 = leaf.increment();

                   l2.print();

 

                   leaf.increment().increment().print();

         }

}

 

 

 

 

6.static:

         1.成员变量的前面

         2.成员方法的前面

         3.{} 前面

public class Person {

                  private static int id;

          静态成员变量在类加载(运行之前)的时候就开始分配空间(dateSegment)并默认初始化

 

         静态成员变量和具体某个对象没有关系~!(

                   因为静态变量是在加载时初始化的,而对象创建在运行期)

                   也可以说:静态变量是“类层面的变量”  而非静态变量是“对象层面的变量”

 

         既然静态变量属于类,那么可以通过类直接访问静态变量。(因为静态变量和对象无关)

                   推荐使用:“类名.静态成员变量”

 

         private int age;       

         //非静态成员变量什么时候初始化?-----运行创建对象的时候

 

         public void m1() {}

 

         public static void m2() { 

         静态方法:都是属于类层面的  和具体对象无关,通过"类名.静态方法()"访问

 

         }

 

         static {  静态代码块  通常用于资源初始化

 

         }

 

         public static void main(String[] args) {

                   main方法为什么要定义成static 类型的

                            现有的技术储备:加载 - 运行(main) - 创建对象.

                                     在main方法执行前,内存中不存在任何对象,只有类

                                     只能通过类调用main方法,所以main方法要定义成static类型的

                  }

}

 

 

public class Person {

         {System.out.println("普通代码块");

         }

 

         static {

                   System.out.println("静态代码块");

         }

 

         public Person() {

                   System.out.println("构造函数");

         }

 

         public static void main() {

                   Person p = new Person();

         }

}

 

 

-----执行顺序

静态代码块 -> 普通代码块 -> 构造函数

 

public static void main(String[] args) {

                  静态方法中直接访问非静态方法,一定出错

                  因为:静态(变量、方法、代码块)是属于“类层面”的,和具体对象无关

                  或者说,无论内存中存不存在对象,静态的一定存在

}

public class Cat {

         private static int sid = 0;

         private String name;

         int id;

 

         Cat(String name) {

                   this.name = name;

                   id = sid++;

         }

 

         public void info() {

                   System.out.println

                            ("My name is " + name + ",No." + id);

         }

 

         public static void main(String[] args) {

                   Cat.sid = 100;           //类名访问静态变量

                   Cat mimi = new Cat("mimi");

                   mimi.sid = 2000;      //对象访问静态变量

                   Cat pipi = new Cat("pipi");

                   mimi.info();

                   pipi.info();

         }

}

 

 

7.继承

         代码冗余  可能发生在(方法内部、类的内部),冗余代码往外踢,遵循“对等原则”

 

         通过继承,子类自动拥有了父类的成员(成员变量和成员方法)

         java只支持单继承,不允许多继承(extends)。接口可以(interface)

public class Person {

         private int id;

         private String name;

         private boolean sex;

 

         public void eat() {

                   System.out.println("Person is eating");

         }

}

 

public class Teacher extends Person{

        

         private int gl;  //教龄

         private String zc;  //职称

 

         public void teach() {

                   System.out.println("Teacher is teaching");

         }

 

}

 

 

public class Student extends Person {

 

         private String school;

         public void study() {

                   System.out.println("Student is studying");

         }

}

解决了代码冗余问题,简洁明了,但是高耦合,Teacher类和 Student类太过依赖 Person类

 

 

 

8.package

         操作一:

         1.在磁盘"e:\a"作为开发目录,存储源文件

         2."e:\a"新建两个java源文件,Test.java和 Person.java

public class Person {

         public static int id = 100;

}

 

public class Test {

         public static void main(String[] args) {

                   Person p = new Person();

         }

}

         编译Test.java就同时得到两个字节码文件,Test.class和 Person.class

 

         操作二:

         1.Test类中可能会用到很多其他的类,为了方便管理 ,我们往往将这些类分类管理

         约定:没有配置classpath,当前的目录结构是"e:\a"

         2.Person.class存储在"e:\a\p"       //相对路径 p        

                  

                   在Person.java源文件的首行使用关键字package

 

         3.Teacher.class存储在"e:\a\t"       //相对路径 t

         4.Student.class存储在"e:\a\s"      //相对路径 s

                   路径:

                            相对路径:相对当前上下文

                            绝对路径:磁盘文件结构:盘符,如:"e:\a"

package t;

public  class Teacher {

         public static int id = 200;

}

 

 

package s;

 

public class Student {

         public static int id = 300;

}

         5.这样做编译后,出错:

                   "错误:无法访问Person类"

         6.正确的编译顺序:

                   先编译被依赖的(Test 依赖于 Person,先编译 Person)

 

                   JDK5.0之后,java源文件有可能会影响到.class的运行,先把Person.java源文件移除掉

 

                   接着把编译后得到的Person.class字节码文件,转移到p文件夹内

                   接着编译Test.java,依旧报错

         7.

                   "错误:找不到符号"

 

                   JVM 首先在当前上下文中寻找Person.class提示找不到符号

 

                   解决方法: 告诉JVM 到p文件夹下加载Person.class 

                   语法:在Person前加上 p.

 

class Test {

         public static void main(String[] args) {

                   p.Person pp = new p.Person();       

         }

}

         8. 再次编译Test.java不出错,运行成功

 

         操作三:

         想把Student放的更深一点,s下的s1,s1下的s2,s2下的s3内

package s.s1.s2.s3;  //磁盘目录/文件夹=====包

 

         public class Test {

                  public static void main(String[] args) {

                            s.s1.s2.s3.Student s = new s.s1.s2.s3.Student();   //全路径类名 -> 反射

                   }

         }

         每次都要书写全路径类名,过于繁琐,于是使用 import 关键字

                   imports.s1.s2.s3.Student;

 

                   imports.s1.s2.s3.Student是相对路径,相对于当前上下文以及classpath

                            所以可以把包的父路径配置到classpath之中去

public class Test {

         public static void main(String[] args) {

                   System.out.println(" ");

         }

}

System:系统内置类,D:jdk1.7.0_60\jre\lib\rt.jar;   

                  rt.jar是压缩文件的一种,压缩多个类        (java特有)

                  .rar  .zip压缩格式

                  rt-> java-> lang ->System.class

         java中lang包的类,JVM 会自动加载,不需要import的导入

 

"D:jdk1.7.0_60\jre\lib\rt.jar"在安装JDK环境的时候,自动配置都classpath里了。

import 包名.类名;          import 包名.*;

 

9.权限控制

 

子类继承父类,那么子类就会“自动拥有”父类的成员。

                  现在考虑的是:子类能不能“直接访问”从父类继承的成员?

 

成员变量定义前可以使用四种修饰关键字:

private int id;

default int id;

protected int id;

public int id;

        

成员变量位置:类内部         同一个包不同类内(含继承)     不同包不同类(含继承)    不同包不同类(没有继承)

private                                 Y                                  N                                                     N                                                              N

default                                 Y                                   Y                                                      N                                                             N

protected                                     Y                                  Y                                                    Y                                                             N

public                                    Y                                  Y                                                    Y                                                              Y

private : 类层面的

default : 包层面的

protected : 子类层面

public : 所有

 

类内部定义了"private"修饰的成员,那么现在测试的是同一个类的内部是不是可以直接访问该变量?

        

 

10.重写

子类继承父类的方法,如果对继承的方法的实现“不满意”,

那么在子类中可以重新定义继承方法的具体实现:重写

 

重载:一个类中的若干方法,如果满足:方法名相同,形参不同

重写:子类“重写”父类继承的方法

         注意                                               public                 void                   eat           ()                         {}

                                                        修饰符              返回值             方法名             形参列表        方法体

                                                        -------------------------------------------------------

                   父类中的方法                                               相              相                          相              不

                   子类重写的方法                                          同              同                                 同              同

 

重写方法必须和被重写方法具有相同方法名称,参数列表和返回类型

 

权限修饰符:从严格到宽松的顺序:private  default   protected  public

                  子类的权限修饰,不能比父类的严格

-----父类-----

public class Person {

         public void eat() {

                   System.out.println("Person is eating");

         }

}

 

-----子类------

public class Teacher extends Person {

         public void eat() {

                   System.out.println("Teacher is eating");

         }

         09

 

         public void teach() {

                   System.out.println("Teacher is teaching");

         }

}

-----子类------

public class Student extends Person {

         public void eat() {

                   System.out.println("Student is eating");

         }

 

         public void study() {

                   System.out.println("Student is studying");

         }

}

 

 

 

11.super

 

创建一个对象,堆内存分配空间,包含所属类中定义的成员变量+this(本身的地址)+super(父对象的地址)

 

子类的构造函数必须调用父类的构造函数

如果调用super,必须写在子类构造方法的第一行

使用this(argument_list)调用本类的另外构造方法

如果子类的构造方法中没有显示的调用父类的构造方法,则系统默认调用父类无参的构造函数

如果子类的构造方法中既没有显示调用父类构造方法,而父类中又没有无参的构造函数,则出错

同一个构造函数中,如果同时出现this和super,this优先

 

class FatherClass {

         public int value;

 

         public void f() {

                   value = 100;

                   System.out.println("FatherClass.value=" + value);

         }

}

 

class ChildClass extends FatherClass {

         public int value;

 

         public ChildClass() {

                   super();

         }

 

         public void f() {

                   super.f();

                   value = 200;

                   System.out.println("ChildClass.value" + value);

                   System.out.println(value);

                   System.out.println(super.value);

         }

}

 

public class Test {

         public static void main(String[] args) {

                   ChildClass cc = new ChildClass();

                   cc.f();

         }

}

 

super:

                  super.成员变量

                  super.成员方法

                  super() 调用父类的无参构造方法

                  return super

 

class Person {

                  public in id;

}

 

class Teacher extends Person {

                  public int age; 

         }

         public Teacher() {

                   //子类构造函数的第一行“一定”是调用父类的构造函数(先创建父对象)

                   //通过关键字super来调用父类构造函数

                   //系统默认调用父类无参构造函数super()

 

                   super();

         }                

}

 

class Test {

         main() {

                   Teacher t = new Teacher();

         }

}

 

---------------------------------------

 

public class Person {

         protected int id;

 

        

         如果没有t显示声明构造函数,那么系统自动提供“无参构造函数”

         如果显示定义了构造函数,那么系统将不再提供“无参构造函数

 

         class Person(int id) {

                   this.id = id;

         }

}

 

class SuperClass {

         private int n;

 

         /*

         SuperClass() {

         System.out.println("SuperClass()");

         }

         */

 

         SuperClass(int n) {

                   System.out.println("SuperClass("+n+")");       //300

                   this.n = n;

         }

}

 

class SubClass extends SuperClass {

         private int n;

 

         SubClass(int n) {

                   //super();

                   System.out.println("Subclass(" + n + ")");

                   this.n = n;

         }

 

         SubClass() {

                   super(300);

                   System.out.println("SubClass()");

         }

}

 

public class TestSuperSub {

         public static void main(String arg[]) {

                   //SubClass sc1 = new SubClass();

                   Subclass sc2 = new Subclass(400);

         }

}

 

 

class A {

        protected void print(String s) {

                 Systme.out.println(s);

        }

        A() {

                 print("A()");

                 public void f() {

                           print("A:f()");

                 }

        }

 

        class B extends A {

                 B() {

                           print("B()");      // 把B()存储内存单元的地址作为实参,传给形参变量

                 }

                 public void f() {

                                    // 重写

                 }

 

                 public static void main(String[] args) {

                           B b = new B();

                 }

        }

 }

 

 输出结果:

        A()  //;

        B()  //;

 

class Person {

         private String name;

         private String location;

 

         public Person(String name) {

                   this.name = name;

                   this.location = "beijing";

         }

 

         public Person(String name,String location) {

                   this.name = name;

                   this.location = location;

         }

 

         public String info() {

                   return "name:" + name + "location:" + location;

         }

}

 

class Student extends Person {

         private String school;

 

         public Student(String name,String school) {

                   !!!super(); 同一个构造函数同属出现this和super,this优先

                   this(name,"beijing",school);

         }

 

         public Student(String name,String location,String school) {

                   super(name,location);     //调用super,创建父类对象

                   this.school = school;

         }

 

         public String info() {

                   return super.info() + "school" + school;

         }

}

 

public class Test {

         public static void main() {

                   Person p1 = new Person("A");

                   Perosn p2 = new Person("B","shanghai");

                   Student s1 = new Student("C","S1");

                   System.out.println(p1.info());

         }

}

 

 

12.Object

 

        定义类:如果一个类没有显示的声明他的父类,那么约定继承自“Object”

        所以也可以说:Object 是所有类的公共父类

 JDK 的安装目录下,有一个src.zip(默认源文件包)

        Object 类中定义的11的成员方法,这11个方法有2个是 protected 修饰,其余都是

                 public 修饰,所以所有类都能继承这11个方法,并且能直接使用

                 1.反射      1个         .getclass

                 2.垃圾回收      1个         finalize

                 3.克隆      1个         clone

                 4.相等      1个         equals + hashCode

                 5.线程      5个           wait notify

                 6.字符串         1个         toString

 

        12.1  .toString()

                 + 如果"+"两侧的操作数有一个是字符串,就表示"连接"操作(即把另一个

                           操作数也变成字符串,然后执行字符串连接操作)

class Person {}

 

                 public class Test{

                           public static void main(String[] args) {

                                    //先把int 型的100转换成“100”

                                    //原因:int 基本类型对应一个引用类型Integer

                                    //Integer 继承了Object 提供的toString()方法,并且重写了toString方法

                                    //把int 整数转化成字符串类型

                                    System.out.println(100+"200");300

 

                                    Person p = new Person();

                                    System.out.println(p);

                                    //对象作为println()方法的参数,观察输出结果:Person@7d206f0

                                    //其实是p.toString()的返回值,作为println()方法的参数输出

                                    //也就是:输出的是对象的toString()的返回值

                                    //即“Person@7d206f0”是Object的toString()方法的默认返回值

                                    //Object 类的 toString()

                                    //return getClass().getName()+"@"+Integer.toHexString(hashCode());     

 

 

                                    // y = f(x)

                                    //x = f-1(y)

                                    //哈希函数,单向不可逆

                                    //已知x通过hash函数可以得到与之对应的唯一的y

                                    }

                 }

 

 

         12.2.  equals()

class Mao {

                   String name;

                   String color;

 

                   Mao(String name,String color) {

                            this.name = name;

                            this.color = color;

                   }

         }

 

         public class Test {

                   public static void main(String[] args) {

                            Integer i1 = new Integer(1);

                            Integer i2 = new Integer(1);

                            Integer i3 = i2;

 

                            /*

                                     public Integer(int value) {

                                               this.value = value;

                                     }

 

                                     public boolean equals(Object obj) {

                                               if (obj instanceof Integer) {

                                                        return value == ((Integer)obj).intvalue();

                                               }

                                               return false;

                                     }

 

                                     public int intvalue {

                                               return value;

                                     }

                            */

 

                            System.out.println(i1==i2);               //false

                            System.out.println(i3==i2);               //true

 

                            System.out.println(i1.equals(i2));

                            //根据分析,i1和i2是分别指向两个对象

                            //而equals默认比较就是比较i1和i2的值,所以比较结果是false

                            //但是运行结果是true

                            //只能是Integer类重写了Object类的equals()

 

                            //构建Integer对象时,两个实参(基本类型int)的“==”比较

 

 

                   }

         }

 

                   生活中有这样一种描述:“相等” “相同” “一样的”

                   java语法:

                            1.==         值的比较

                                     基本数据类型:int i= 10;      int j = 20; boolean  flag=i==j;

                                               //flag= false;

                            2.equals

                                     当进行两个对象是否“相同”的比较判断时,使用Object类提供的equals方法

 

                                      1.equals()方法应用的情形:

                                               用于两个对象是否“相同”的情景

                                     2.语法:

                                               obj1.equals(obj2);

                                     3.方法的返回值:

                                               如果obj1和obj2“相同”返回true,不同返回false;

                                     4.何为“相同”何为“不同”

                                               结合具体业务情况

                                     5.如果不指定“相同”的条件,JVM怎么判断?

                                               Object父类中的equals方法已经对两个对象“相同”做了默认设置

 

                                               publicboolean equals(Object obj) {

                                                        return(this == obj);

                                               }

 

                                               所以:默认比较的还是两个对象的地址

 

 

                                     6.当需求涉及到自定义类的对象进行相同比较时,一般都需要重写equals方法

 

 

 

 

13.对象转化

 

 

需求场景:继承 子类  父类

         1. 子类类型的变量去指向子类

                   Teacher t =new Teacher();

 

         2.父类类型的变量指向子类(推荐使用)

                   Person p1 =new Teacher();

                   Person p2 =new Student();

 

         3.问题:父变量指向子类对象有什么特殊的地方 ?

                   3.1 父变量可以访问子类从父类继承而来的方法和属性

                   3.2 父变量不可以访问子类新增的成员

 

         4. 向上转型 (父变量指向子类对象)

 

         5. instanceof (操作符)

                   左侧:变量

                   右侧:类名

                   引用型变量instanceof 类名

                   含义:引用型变量是不是类或者其子类的对象(实例)?

 

                   Person p1 =new Person();

                   Person p2 = newTeacher();

                   System.out.println(p1instanceof Preson);    //变量p1指向的对象是不是Person类型的对象? true

                   System.out.println(p1instanceof Teacher);    //

 

class Person {

         String name;

 

         public void eat() {

                   System.out.println("Person is eating");

         }

}

 

class Tescher extends Person {

         String zc;

 

         public void teach() {

                   System.out.println("Teacher is teaching");

         }

}

 

class Student extends Person {

         String xh;

 

         public void study() {

                   System.out.println("Student is studying");

         }

}

 

public class Test {

         public static void main(String[] args) {

                   Teacher t = new Teacher();

                   Student s = new Student();

 

                   Person p1 = new Teacher();

                   Person p2 = new Student();

         }

}

 

//重写Cat 的 equals()

class Cat {

         private String name;

         private String color;

 

         public Cat(String name,String color) {

                   this.name = name;

                   this.color = color;

         }

}

 

 

public boolean equals(Object obj) {

         //首先确定obj的类型

         if (!obj instanceof Cat) {

                   return false;

         }

 

         //比较c1和c2的name属性,color属性是否相同

         //问题:this能不能访问到name属性----能,name属性属于调用equals()方法的对象,即c1

         //问题:obj能不能访问到name属性----不能,父变量obj指向子类对象c2,而name属性是子类对象c2新增的

        

         //问题:父变量怎么去访问子类新增的成员?

         //答:(向下转型)强制类型转换,把父变量转换为子类变量(大的给小的)

 

         Cat c = (Cat) obj;

         //this.name.equals(obj.name);

 

         return this.name.equals(c.name);

 

}

 

main() {

         Cat c1 = new  Cat("A","A");

         Cat c2 = new  Cat("A","A");

 

         System.out.println(c1.equals(c2));

}

 

 

14. 多态(访问并继承的方法)

//父类:

class Person {

         public void eat() {

                   System.out.println("Person is eating...");

         }

}

 

                   //子类1

class Teacher extends Perosn {

         public void eat() {

                   System.out.println("Teacher is eating...");

         }

}-

 

 

                   //子类2

class Student extends Person {

         public void eat() {

                   System.out.println("Student is eating...");

         }

}

 

         //测试类 父变量指向子类对象,然后通过父变量访问子类从父类继承并重写的方法

         //问题:方法在父类中有,每个子类对中也有,那么通过父类访问这个方法,这个方法到底是谁的?

 

public class Test {

         private static void main(String[] args) {

                   Person p1 = new Teacher();

                   p1.eat();  //Teacher is eating...

 

                   Person p2 = new Student();

                   p2.eat();  //Student is eating...

         }

}

 

前提条件:

                  1. 存在继承关系

                  2. 子类重写了从父类继承的方法

                  3. 父变量指向子类对象

 

结论:

                  多态(动态绑定)通过父类调用方法:那么这个方法是:子类重写后的方法

                            那么父变量具体指向哪个子类对象,这个方法就是该子类的对象

                   动态:父变量理论上可以指向任何一个子类对象,比如:p=new Student();p=new Teacher();

                   绑定:访问的方法,和父变量当前指向的那个子类对象“绑定”

 

15.抽象方法/类

 

多态的效果:父变量访问方法,方法是父变量当前指向的那个子类对象重写后的方法

问题:父类中的方法的方法体无论如何都执行不了

自然想到:父类方法的方法体既然不能被访问到,那么它就没有实现的必要

====> 结论:在多态环境下,父类被子类重写的方法,只有“定义”的必要,没有“实现”的必要

                   只要{}存在,方法就是实现了。即使{}里面什么都没有,这叫空实现

                   方法定义:权限   返回值类型  方法名()

                                      public    void       eat()

                   但问题又来了:这违背了我们之前掌握的理论:方法遵循“定义”“赋值/实现”“访问”

====> 解决方法:在方法的定义中假如关键字“abstract”(抽象的)

 

         结论:

                   抽象方法,只有定义,没有实现。称为“抽象方法”

                   抽象类:包含抽象方法,一定要“定义”成抽象类 ===>即使没有包含抽象方法,这个类一样可以定义成抽象类

 

 

特性:

                  抽象方法必须必重写(完善实现)

                  抽象类“天生”就是被继承的

                  抽象类不能被直接实现=====>不能被实例化

 

 

16.final

         默认名称全大写

 

         1.修饰变量 不变的变量,即变量值不能更改

         2.修饰方法(不能被重写)

         3.修饰类(不能被继承);

 

class Person {

         private String name;                  // 变量,属性 attribute   property

        

         public Person(String name) {

                   this.name = name;

         }

 

         // 取值方法  getter或者setter方法命名约定:set/get + attribute首字母大写

         public String getName() {         // get方法后缀首字母变小写后得到的单词:property

                   return name;

         }

 

         // 赋值

         public void setName(String name) {

                   this.name = name;

         }

}

class Test {

         public static void main(String[] args) {

                   Person p = new Person("zs");

                  

                   // 获取对象的private属性值

                   System.out.println(p.name);  // error 封装

                   System.out.println(p.getName());  // zs

 

                   // 重新给name属性赋值

                   p.setName("ls");

         }

}

 

 

重写@Override

         @Override

         public void eat() {

                   // TODO Auto-generated method stub

                   super.eat();

         }

你可能感兴趣的:(J2SE第三章——面向对象(二))