JavaSE学习笔记之-----面向对象

目录:

一、面向对象基本概念

二、引用变量与对象

三、构造方法(函数)

四、方法的重载

五、this关键字和static关键字

    1、this关键字

    2、static关键字

六、package和import语句

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

一、继承

二、方法的重写

三、super关键字

四、Object类    

五、对象转型

六、多态

七、抽象类

八、Final关键字

九、接口(interface)



一、面向对象基本概念

     Java中面向对象和C++中基本一致,就思想来说,其实都一样的,只是有些概念或者叫法有些不同。Java当中分清楚类、对象、方法这三者就行了。对象有的时候叫实例,而方法其实就是函数,来完成某一功能的。

   我对类的理解是: 类是一个抽象的概念,是不存在的东西,是从众多具体的事物(即是程序中叫的对象、实例)中概括出的共性,它只是一个概念,比如说“水果”、“蔬菜”,这些都是类,因为不存在一个“东西”叫“水果”,比方说走进水果店,跟老板说,老板:我要买水果;老板问你是不是要苹果;你答:不是要苹果,我就是要水果;这个例子中的“水果”就是类,苹果就是对象。对象是实际存在的实例,是具备了“类”的特征的“东西”。同样,在程序中,你需要用“类”去实例化一个“对象”。

    方法实际上就是函数了,在类里面有类的成员变量(也叫属性),还有类的方法,这些类的方法实际上就是完成某些特定功能的代码片段了。

    *对象是Java程序的核心,“万事万物皆对象”

    *对象可以看成是静态属性(成员变量)和动态属性(方法)的封装体

    *类是用来创建同一类型的对象的“模板”,在同一类中定义了该类对象所应具有的成员变量以及方法


小知识点:

    1、成员变量可以不赋初值就使用,如果不赋初值,int型初值为0,double型初值为0.0;但是局部变量一定要赋初值才能使用,比如说,int i;这个如果是定义在局部变量里的,那在使用i之前一定要对i进行赋初值。

   2、类是一个静态的概念,存在于代码区(code segment )。

        对象是new出来的,存放于堆内存。类的每个成员变量在不同的对象中都有不同的值(静态变量static除外),但是方法只有一份,只有在方法执行的时候才占用内存。


二、引用变量与对象

    Java当中,除了基本类型之外的变量类型都称之为引用。Java中的对象是通过引用,来对其操作的。引用的实质类似于C语言的指针。下面代码:

    

Circle myCircle = new Circle();
    我们常常讲myCircle就是一个Circle的对象,在和别人交流的时候不严格区分对象和引用变量二者区别的时候可以这样说。不过要从实际底层工作上来讲,并非如此。myCircle是一个变量,叫做引用变量,它并不是对象本身,这个变量里面存放了一个地址,这个地址就是new Circle()这个对象在堆上的位置。这个过个过程类似指针,操作对象,并不是直接去操作对象,而是通过操作指向这个对象的引用变量。

    引用是存储在栈(stack)空间上,而对象本身是存放在堆(heap)空间上,对象可以有多个引用指向它,也可以没有引用指向它。如下代码:


new Circle();
在堆空间上创建了一个Circle的对象,但是并没有引用指向它。(这种情况下,这个对象实际上是垃圾,会被GC掉,但一般不会立即被GC)

Person person1;
person1 = new Person("张三");
Person person2;
person2 = new Person("李四");
person1 = person2;

    前面四行,person1和person2分别指向对象张三和对象李四。第五行,看起来像是对象李四赋值给了对象张三。实际上并不是对象本身在进行复制,而是引用变量在复制,复制结束以后,在对空间上仍然有对象张三和对象李四,只是原本指向对象张三的引用变量person1指向了对象李四。程序结束以后,对象张三便没有引用变量指向它了。并且,对象李四此时,有两个引用变量指向它。

    上面代码在执行完第一行时,person1并不指向任何对象,它的值是NULL。

小知识点:

    1、必须使用new关键字创建对象;

    2、使用引用.成员变量来使用对象的成员变量;

    3、使用引用.方法(参数列表)来调用对象的方法;

    4、同一类的每个对象有不同的成员变量存储空间;

    5、同一类的每个对象共享该类的方法。

更详细的介绍引用变量和对象的博客:www.cnblogs.com/dolphin0520/p/3592498.html

                                                                    zwmf.iteye.com/blog/1738574


三、构造方法(函数)

    Java构造函数和C++一样,在new出一个新对象以后,用来初始化对象的。

    有两个特点,一是无返回类型;二是方法名与类名完全一致。

    

public class Person {
  int id;
  int age;
  Person(int _id,int _age) {
    id = _id;
    age = _age;
  }
}

    在创建Person对象的时候,会调用Person的构造函数,例如:

Person person1 = new Person(1,25);

    右侧的Person必须要把参数传进去,用来初始化对象的成员变量,如果你没有写Person的构造函数,那可以不用传参数进去(编译器会自动添加一个构造函数),编译器会把成员变量的值初始化为0.

    约定俗成的命名规则:

        *类名的首字母大写;

        *变量名和方法名首字母小写;

        *运用驼峰标识,例如myCircle。


四、方法的重载

    方法的重载是指一个类中可以定义有相同的名字,但参数不同的多个方法。(参数不同体现在两个方面,可以是参数个数不相同,也可以是参数类型不一样)。在调用的时候可以根据不同的参数表选择对应的方法。(根据传入的形参不一样,来找到不同的方法)。

    如下代码,有如下方法:

void info() {
    System.out.println("My id is"+id);
}
void info(String t) {
    System.out.println(t+" "+id+""+age);
}

    在调用的时候,如下:

public class Test {
  public static void main (String args[]) {
    Person p = new Person(1,20);
    p.info();
    p.info("Hello");
  }
}

    在调用的时候可以根据传入的参数不同找到对应的方法,这即是重载。

构造方法也可以重载,如下代码:

Person() {
  id = 0;
  age = 20;
}
Person(int i) {
  id = 0;
  age = i;
}
Person(int _id ,int _age) {
  id = _id;
  age = _age;
}

    在new对象的时候:

Person p1 = new Person();
Person p2 = new Person(20);
Person p3 = new Person(1,20);

    new出来的三个对象都是不一样的初始值。


五、this关键字和static关键字

    1、this关键字

    <1>this关键字有几种用法,最常用的应该是处理方法中的成员变量和参数重名的情况,如下:

public class Test{
        String name;
        void na(String name){
             this.name  = name;
     }
}

this.name指的是成员变量,name指的是传进来的形参。

    <2>在实现构造函数的时候,使用this()来调用另外一个构造函数


关于this关键字的详细使用参考博客:blog.csdn.net/anmei2010/article/details/4091227


    2、static关键字

    静态变量存储在data segment中,在类中,用static声明的成员变量是静态成员变量,它是该类的公共变量,对于该类的所有对象来说,static成员变量只有一份。任何一个对象去修改该变量,对所有对象都有影响。

    用static声明的方法为静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中,不可以访问非static的成员。

    静态方法不再是针对于某个对象调用,可以通过 对象引用或者类名(不需要实例化)访问静态成员。


六、package和import语句

    java为了避免类的命名冲突问题,引入了包(package)机制,提供类的多重类命名空间。

    比如说,我写了一个类Cat,要在另外一个类当中使用Cat类,但是可能还会有其他的程序员或者自己以前编写过Cat类,名字相同了,为了区分我要找的是我现在编写的这个Cat类,那么就使用package打包。例如Cat类代码如下(就写一个空类):

package com.ys;

public class Cat {

}

    package语句必须出现在源代码第一行,(注释除外)。上面代码表示说,我有一个类包在com.ys里面,当编译完这个源代码以后生成class文件。现在我要在Test这个代码里面调用Cat类,调用的代码如下:

public class Test {
  public static void main(String [] args) {
      Cat c = Cat();
  }
}

我直接调用Cat这个类,但是会报错,找不到类,因为Cat类被打包在com.ys中,那么要把Cat写全了:

public class Test {
  public static void main(String [] args) {
      com.ys.Cat c = com.ys.Cat();
  }
}

    但是这样写又会显得特别麻烦,每一次写Cat类都要写全,这时候import就派上用场了,代码改为如下;

import com.ys.Cat;

public class Test {
  public static void main(String [] args) {
      Cat c = Cat();
  }
}

   这样在开头作声明引入了Cat类,下面的代码就可以直接使用了。

    不过此时要注意编译生成的Cat.class文件和Test.java源代码的文件目录位置必须是如下:

JavaSE学习笔记之-----面向对象_第1张图片


com目录下面:

JavaSE学习笔记之-----面向对象_第2张图片


ys目录下面:

JavaSE学习笔记之-----面向对象_第3张图片  

    就是说打了几级包就得把目录都建全,并且最上面的父目录(这里是com目录)要和调用该类的那个源文件(这里是Test.java)在同一级目录下。

    如果一个类打包了,那么编译后的class文件在执行的时候(javac)也要写全名。


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

                                                                                      以下内容为2016/7/18更新

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

一、继承

    继承使用关键字extends,使用继承,子类继承了父类所有的成员(属性和方法),Java只能允许单继承,一个子类只能有一个父类,Object类是所有类的根基类,所有的类默认从Object类继承。

JavaSE学习笔记之-----面向对象_第4张图片


前面不写修饰符,就默认是default。


二、方法的重写

    子类从父类继承来的方法不满意,可以自己再重写该方法。

    1、返回类型 2、方法名 3、参数列表。

    这三点一定要一模一样,并且子类重写的方法不能比父类的访问权限更加严格,比如父类方法的修饰符是protected,那子类重写的方法只能是protected或者是public。


三、super关键字

    1、super关键字可以引用父类的方法,比如说现在子类继承一个父类,重写了父类的方法,但是现在又想要调用父类的方法,那么就可以用super关键字来实现。形如super.info();

    2、子类继承父类的时候,子类的构造函数在实现的时候,必须要调用父类的构造函数,因为实际上new一个对象的时候,要通过构造函数来实现,而子类对象在实现的时候是包含父类对象的,那么要想new出子类对象先要new出父类对象。在子类对现的构造函数当中,如果没有显示的调用super,那么就会自动的去调用父类的无参构造函数,如果此时父类有一个构造函数,但是该构造函数不是无参的,那此时会报错。如果父类没有任何显示的构造函数,那么编译可以通过。父类和子类都不写任何构造函数,也是可以的。

class SuperClass {
    private int n;
  	
  	/*
    SuperClass() {
        System.out.println("SuperClass()");
    }*/
    
    
    /*
    SuperClass(int n) {
        System.out.println("SuperClass(" + n + ")");
        this.n = n;
    }*/
}

class SubClass extends SuperClass {
    private int n;
       
    SubClass() {
    		//super(300);
        System.out.println("SubClass()");
    }
    
    SubClass(int n) {   		
        System.out.println("SubClass(" + n + ")");
        this.n = n;
    }
    
}

public class TestSuperSub {
    public static void main(String arg[]) {
        SubClass sc1 = new SubClass();
        //SubClass sc2 = new SubClass(40);
    }
}

new  sc1的时候,先调用父类构造函数,没有显示调用super,所有自动去调用父类的无参构造函数,但是父类没写无参构造函数,这样也可以编译通过。输出结果是

但如果此时,父类有一个有参的构造函数,那么程序就会出错,就是父类的SuperClass(int n)  的构造方法的注释去掉的话,编译就会出错。一定要保证父类没有任何的构造函数,才可以不显示调用super


上面代码如果改成,把父类的无参构造函数的注释去掉,

class SuperClass {
    private int n;
  		
    SuperClass() {
        System.out.println("SuperClass()");
    }
     
    /*
    SuperClass(int n) {
        System.out.println("SuperClass(" + n + ")");
        this.n = n;
    }*/
}

class SubClass extends SuperClass {
    private int n;
       
    SubClass() {
    		//super(300);
        System.out.println("SubClass()");
    }
    
    SubClass(int n) {   		
        System.out.println("SubClass(" + n + ")");
        this.n = n;
    }
    
}

public class TestSuperSub {
    public static void main(String arg[]) {
        SubClass sc1 = new SubClass();
        //SubClass sc2 = new SubClass(40);
    }
}


那么输出就会是:


调用super的时候一定要写在构造函数的第一行。


下面有一个小程序,包含了继承、重写、this的用法,super的用法。

class Person {
	String name;
	String location;
	
	Person(String name) {
		this.name = name;
		location = "BeiJing";
	}
	Person(String name,String location) {
		this.name = name;
		this.location = location;
	}
	public void info() {
		System.out.println("name: "+name+" location: "+location);
	}
}

class Student extends Person {
	String school;
	Student(String name,String school) {
		this(name,"BeiJing",school);
	}
  Student(String name,String location,String school) {
  	super(name,location);
  	this.school = school;
  }
  public void info() {
  	System.out.println("name: "+name+" location: "+location+" school: "+school);
  }
}

class Teacher extends Person {
	String job;
	Teacher(String name,String job) {
		this(name,"BerJing",job);
	}
	Teacher(String name,String location,String job) {
		super(name,location);
		this.job = job;
	}
	public void info() {
		System.out.println("name: "+name+" location: "+location+" job: "+job);
	}
}

public class TestTeacher {
	public static void main(String[] args) {
		Person p1 = new Person("person1");
		Person p2 = new Person("person2","ShangHai");
		Student s1 = new Student("studen1","school1");
		Student s2 = new Student("student2","ShangHai","school2");
		Teacher t1 = new Teacher("teacher1","teaching");
		Teacher t2 = new Teacher("teacher2","ShangHai","teaching");
		p1.info();
		p2.info();
		s1.info();
		s2.info();
		t1.info();
		t2.info();
	}
}

输出结果是:

JavaSE学习笔记之-----面向对象_第5张图片


四、Object类    

这是所有类的父类,定义类的时候只要没有使用extends,那么久默认定义为从Object类继承。

   1、toString方法

    这个tostring方法的功能是返回一个代表本对象的字符串,该字符串前面是类名,后面是一个@号加上哈希编码。从Object类继承的类要实现该方法,几乎都是要重写。

    2、equals方法

    这个方法是比较两个对象是否相等,但是它比较的实际上是两个对象的引用是否相等,同一个类new出来的两个引用就存放着两个不同的对象的地址,当然是不可能相等的,所以要比较对象是否相等也是要重写方法的。


五、对象转型

    就是指向父类的引用,可以指向子类对象。

    举个例子,Animal是父类,Cat是子类,

Animal  a = new Animal();
Cat c = new Cat();
a = c;

上面代码,a是父类引用类型变量,它是指向对空间的Animal对象的。c 是指向对空间中Cat对象的,Cat从Animal继承而来,它有属于自己的属性和方法,相当于是子类包含父类的概念。然后c复制给a,那么a和c的值应该一样,都指向Cat对象,但是,a的类型是Animal类型,所以说它虽然指向Cat对象,但是它却把Cat对象当成是Animal,它只能看见Animal类所包含的属性和方法,独属于Cat类的属性和方法a是看不见的。如何解决这个问题,就用对象转型,如下面一行代码就行了:

a = (Cat)a;

强制类型转换,这样a就能访问Cat中的全部内容了。


六、多态

    满足:1、有继承 2、有重写 3、父类引用指向子类对象。就可以有多态

    在程序”执行”期间,判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

    用下面的程序:

class Animal {
	String name;
	Animal(String name) {
		this.name = name;
	}
	public void info() {
		System.out.println("I am Animal");
	}
}

class Cat extends Animal {
	String color;
	Cat(String name,String color) {
		super(name);
		this.color = color;
	}
	public void info() {
		System.out.println("I am Cat");
	}
}

class Person {
	String name;
	Animal pet;
	Person(String name,Animal pet) {
		this.name = name;
		this.pet = pet;
	}
	public void info() {
		pet.info();  //调用Animal的方法
	}
}

public class poly {
	public static void main(String[] args) {
		Animal a = new Animal("pet");
		Cat c = new Cat("cat","balck");
		Person p1 = new Person("p1",c);	
		p1.info();
	}
}


本来Person类的第二个参数应该是Animal类型的引用变量,但是实际上传进去的是Cat类的,程序会根据实际的类型,调用对应的方法,所以最后调用的是Cat的info方法,而不是Animal的info方法。


七、抽象类

    1、用abstract关键字来修饰一个类时,这个类叫做抽象类;用abstract来修饰一个方法时,该方法叫做抽象方法;

    2、含有抽象方法的类,必须被继承,抽象方法必须被重写;

    3、抽象类不能被实例化,不能new对象;

    4、抽象方法只需声明,而不需被实现。

抽象类就是说,父类定义一个方法,但是没法确定这个方法的具体实现,比如被不同的类继承去了,有不同的方法实现,但是父类可以确定这个方法是需要的,只是暂时还不知道实现过程,此时就可以定义抽象方法。如下程序:

abstract class Animal {
	private String name;
	Animal(String name) {
		this.name = name;
	}
	public abstract void enjoy();
}

class Cat extends Animal {
	private String eyesColor;
	Cat(String n,String c) {
		super(n);
		eyesColor = c;
	}
	public void enjoy() {
		System.out.println("Cat voice....");
	}
}

八、Final关键字

    类似于C的const关键字,被final修饰以后的变量,值不能被改变,不论成员变量还是局部变量;final的方法不能够被重写;final的类不能够被继承。记住这几点就行了。


九、接口(interface)

    接口是一种特殊的抽象类。定义接口关键字是interface,实现接口(也可以说继承接口),使用的是implement关键字。

   接口当中只有常量和方法的定义,而没有变量和方法的实现

JavaSE学习笔记之-----面向对象_第6张图片


在接口中即使不写public static final,默认也会这个格式。

下面程序体现了接口的应用,以及隐含的多态实现

interface Singer {
	public void sing();
	public void sleep();
}
interface Painter {
	public void paint();
	public void eat();
}

class Student implements Singer {
	private String name;
	Student(String name) {
		this.name = name;
	}
	public void study() {
		System.out.println("studying");
	}
	public String getName() {
		return name;
	}
	public void sing() {
		System.out.println("Student is singing");
	}
	public void sleep() {
		System.out.println("Student is sleeping");
	}
}

class Teacher implements Singer,Painter {
	private String name;
	public String getName() {
		return name;
	}
	Teacher(String name) {
		this.name = name;
	}
	public void teach() {
		System.out.println("teaching");
	}
	public void sing() {
		System.out.println("Teacher is singing");
	}
	public void sleep() {
		System.out.println("Teacher is sleeping");
	}
	public void paint() {
		System.out.println("Teacher is painting");
	}
	public void eat() {
		System.out.println("Teacher is eating");
	}
}
public class test {
	public static void main(String args[]) {
		Singer s1 = new Student("stu");
		s1.sing();
		s1.sleep();
		Singer s2 = new Teacher("tea");
		s2.sing();
		s2.sleep();
		Painter p1 = (Painter)s2;
		p1.paint();
		p1.eat();
	}
}

JavaSE学习笔记之-----面向对象_第7张图片

Singer s1 = new Student("stu");

这一行代码,new出一个Student的对象,引用s1指向这个对象,但是,s1是Singer类型的引用,它只能看到Student对象当中Singer的部分,即是它只能访问Student当中的sing和sleep方法,而无法访问study方法。

Painter p1 = (Painter)s2;

这一行是先定义一个Painter类型的引用变量p1,s2本来是Singer类型的,它指向Teacher的一个对象,但是只能看到Singer的部分,即是只能访问sing和sleep方法,但是将s2强制转换成Painter类型,那么它即能访问到Teacher中Painter的部分,即是paint和eat方法。



你可能感兴趣的:(JavaSE学习笔记)