Java学习笔记(一)面向对象(OOP)

面向对象:

面向过程编程:一堆方法,调来调去
面向对象编程:以对象为核心,围绕着对象做操作
面向接口编程:面向对象的基础之上,抽接口
    好的代码:复用性好、可维护性好、可扩展性好、移植性好......

面向过程:实在  

    缺陷一:缺乏对数据的封装
    缺陷二:数据和方法分离状态


面向对象:抽象

  1.现实世界是由很多对象组成的
  2.现实世界是先有对象,再抽出类。代码中先创建类,再创建对象
  3.一个类可以创建多个对象,同一个类的多个对象,结构相同,数据不同
  4.类是一种数据类型 只能包含:
    1)描述对象所共有的特征:------变量。属性-----静的

    2)对象所共有的行为:----------方法。行为-----动的

  5.new后,成员变量有默认值

  6.创建对象语法:
    类名 引用 = new 类名();
    其中:new 类名()是在创建对象
    因对象为数据,所有声明引用来指代数据
  7.访问成员变量、访问方法     ----通过点来操作,语法:
    引用.成员变量
    引用.方法名();
  8.基本类型之间画等号----再赋值------身份证复印件
   引用类型之间画等号----指向同一个对象------房子钥匙
  9.null:空,表示没有指向对象
    若引用的值为null,则不能再进行点操作,
    否则会出现NullPointerException异常

8种基本类型:可以直接赋值
除了8种之外:
类、接口、数组----引用类型    都是通过new出的

1.基本:
  直接赋值
  变量装的就是确切的值
  画等号----赋值
  int num = 5;
2.引用:
  new
  变量装的是地址
  画等号----指向同一个对象

3.引用类型数组
  int[] arr = new int[4];    arr指向 一个int[]类型的地址, 这个地址的大小是4个int类型的大小。
  Cell[] cells = new Cell[4];  cells指向一个Cell[]类型的地址,这个地址的大小是4个Cell类型的大小

 

java建议:
  1个文件只包含1个类

java规定:
  java中一个文件可以包含多个类,
  但是,public的类只能有1个,
  并且,public的类必须与文件名相同

Java中的类

类可以看成是创建Java对象的模板。

public class Dog{
  String breed;
  int age;
  String color;
  void barking(){
  }
 
  void hungry(){
  }
 
  void sleeping(){
  }
}

  

一个类可以包含以下类型变量:

  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
  • 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。

一个类可以拥有多个方法,在上面的例子中:barking()、hungry()和sleeping()都是Dog类的方法。

 

构造方法

  1.构造方法常常用于给成员变量初始化
  2.与类同名,没有返回值类型
  3.构造方法是在创建对象时被自动调用
  4.若自己不写构造方法,则编译器默认给一个无参构造,若自己写了,则不再默认提供无参构造
  5.构造方法可以重载

public class Puppy{
    public Puppy(){
    }
 
    public Puppy(String name){
        // 这个构造器仅有一个参数:name
    }
}

创建对象

对象是根据类创建的。在Java中,使用关键字new来创建一个新的对象。创建对象需要以下三步:

  • 声明:声明一个对象,包括对象名称和对象类型。
  • 实例化:使用关键字new来创建一个对象。
  • 初始化:使用new创建对象时,会调用构造方法初始化对象。
    public class Puppy{
       public Puppy(String name){
          //这个构造器仅有一个参数:name
          System.out.println("小狗的名字是 : " + name ); 
       }
       public static void main(String []args){
          // 下面的语句将创建一个Puppy对象
          Puppy myPuppy = new Puppy( "tommy" );
       }
    }  
/* 实例化对象 */
ObjectReference = new Constructor();
/* 访问类中的变量 */
ObjectReference.variableName;
/* 访问类中的方法 */
ObjectReference.MethodName();

实例

下面的例子展示如何访问实例变量和调用成员方法:

public class Puppy{
   int puppyAge;
   public Puppy(String name){
      // 这个构造器仅有一个参数:name
      System.out.println("小狗的名字是 : " + name ); 
   }
 
   public void setAge( int age ){
       puppyAge = age;
   }
 
   public int getAge( ){
       System.out.println("小狗的年龄为 : " + puppyAge ); 
       return puppyAge;
   }
 
   public static void main(String []args){
      /* 创建对象 */
      Puppy myPuppy = new Puppy( "tommy" );
      /* 通过方法来设定age */
      myPuppy.setAge( 2 );
      /* 调用另一个方法获取age */
      myPuppy.getAge( );
      /*你也可以像下面这样访问成员变量 */
      System.out.println("变量值 : " + myPuppy.puppyAge ); 
   }
}

  

当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。

  • 一个源文件中只能有一个public类
  • 一个源文件可以有多个非public类
  • 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
  • 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
  • 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
  • import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。

类有若干种访问级别,并且类也分不同的类型:抽象类和final类等。

  

this:
  1.this指代当前对象,谁调指的就是谁
  2.用法:
    this.成员变量---访问成员变量
    this.方法()-----访问方法
    this()--------调构造方法

继承:

  避免代码重复
  父类中包含所有子类公有的数据
  子类中包含子类所特有的数据

企鹅类:

public class Penguin { 
    private String name; 
    private int id; 
    public Penguin(String myName, int  myid) { 
        name = myName; 
        id = myid; 
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"         + id + "号" + name + "."); 
    } 
}

 老鼠类:

public class Mouse { 
    private String name; 
    private int id; 
    public Mouse(String myName, int  myid) { 
        name = myName; 
        id = myid; 
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"         + id + "号" + name + "."); 
    } 
}

  从这两段代码可以看出来,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类:

public class Animal { 
    private String name;  
    private int id; 
    public Animal(String myName, int myid) { 
        name = myName; 
        id = myid;
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"         + id + "号" + name + "."); 
    } 
}

  企鹅类:

public class Penguin extends Animal { 
    public Penguin(String myName, int myid) { 
        super(myName, myid); 
    } 
}

  老鼠类:

public class Mouse extends Animal { 
    public Mouse(String myName, int myid) { 
        super(myName, myid); 
    } 
}

  

继承的特性

  • 子类拥有父类非private的属性,方法。

  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。

  • 子类可以用自己的方式实现父类的方法。

  • Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,这是java继承区别于C++继承的一个特性。

  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系)。

extends关键字

在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。

public class Animal { 
    private String name;   
    private int id; 
    public Animal(String myName, String myid) { 
        //初始化属性值
    } 
    public void eat() {  //吃东西方法的具体实现  } 
    public void sleep() { //睡觉方法的具体实现  } 
} 
 
public class Penguin  extends  Animal{ 
}

 

super 与 this 关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

this关键字:指向自己的引用。

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

  

输出结果为:

animal : eat
dog : eat
animal : eat

父类类型引用指向子类的对象---向上造型

动物是老鼠--------------语义不通
Mouse m = new Animal(); //错误

 

Person p = new Student(); //向上造型
Person p = new Teacher();
Person p = new Doctor();

public class Test {
	public static void main(String[] args) {
		Animal a = new Animal("动物");
		Dog d = new Dog("小明");
		sleep(a);
		sleep(d);
	}
	
	public static void sleep(Animal a){//可以接受任何Animal类型与Animal子类类型。
		a.sleep();		//调用对应的方法
		
	}
}

class Animal{
	String name;
	public Animal(String name){
		this.name = name;
	}
	public void sleep(){
		System.out.println(name+"正在睡觉");
	}
}

class Dog extends Animal{
	
	public Dog(String name) {
		super(name);
	}

	public void sleep(){
		System.out.println(name+"是条狗,"+"正在睡觉。");
	}
}

  输出:

    动物正在睡觉
    小明是条狗,正在睡觉。

向上造型:父类引用指向子类对象
  注意:能点出来什么,看类型

重写(override)和重载(overload)的区别------常见面试题
重载:
  在一个类中,方法名相同,参数列表不同
重写:
  在两个类中,并且是子类和父类的关系,签名相同

重载:编译时----.java到.class的过程
  内存没东西---只看语法对不对

重写:运行时----jvm加载.class并运行.class的过程内存才有东西

堆、栈、方法区------jvm分配的内存

 

重载时调用看类型,重写时调用看对象

方法的重写:发生在两个类中,并且两个类是继承关系 。子类方法与父类方法的签名相同时     ----  子类重写了父类的方法。

public class Test {
	public static void main(String[] args) {
		Coo c = new Coo();
		Aoo a = new Boo();
		c.print(a);
	}
	
}

class Aoo{
	public void show(){
		System.out.println("from Aoo");
	}
}
class Boo extends Aoo{
	public void show(){
		System.out.println("from Boo");
	}
}
class Coo{
	public void print(Aoo a){
		System.out.println("from Coo print(Aoo a)");
		a.show();
	}
	public void print(Boo b){
		System.out.println("from Coo print(Boo b)");
		b.show();
	}
}

  输出:

from Coo print(Aoo a)
from Boo

  

package 关键字

建议
域名反写 项目名称 模块名称
com.xxx.studentmanager.course.类名

package a.b.c.d.e; //声明包
public class Test{
}

//a.Test----全局限定名
a.b.c.d.e.Test o = new a.b.c.d.e.Test();

import a.b.c.d.e.Test; //声明类、引入类
Test t = new Test(); //创建对象


import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;

import java.util.*;    //---------不建议导入所有类
  

Scanner scan = new Scanner(System.in);

java.util.Scanner scan = new java.util.Scanner(System.in);//也可以用全称。

  同一个包中的类不需要import

访问修饰符:public,private,protected,默认

 

     访问权限   类    包  子类  其他包

        public     ∨     ∨     ∨     ∨          (对任何人都是可用的)

        protect    ∨     ∨    ∨     ×    (继承的类可以访问以及和private一样的权限)

        default    ∨     ∨     ×     ×    (包访问权限,即在整个包内均可被访问)

        private    ∨     ×     ×     ×    (除类型创建者和类型的内部方法之外的任何人都不能访问的元素)

 

static:

成员变量:
  1)实例变量-----不用static修饰的
  2)静态变量-----static修饰的

何时用静态变量,何时用实例变量
class Customer{ //帐户类
  String customerName; //帐户名称
  String customerPwd; //帐户密码
  static double poir; //利率
}
实例变量:属于对象,一个对象有一份
静态变量:属于类,所有对象公用这一份

class Aoo{
   int a;-------------属于对象
   static int b;------属于类
   void show(){
     b++;
   }
}

类的方法中,常常需要对对象的实例变量操作
类的非静态方法,默认有个隐式的this
类的静态方法,没有隐式的this的

class Cell{
   int row;  //属于对象---实例变量
   int col;  //属于对象---实例变量
   static int num;
   static void show(){
      row++;   //错误的
      num++;   //正确的

      Cell c = new Cell();
      c.row = 5;
   }
   void drop(){
      this.row++;
   }
   void moveLeft(){
      this.col--;
   }

}

非静态方法:---有隐式this
  可以直接访问静态变量和实例变量
  需要访问实例变量时用

静态方法:-----没有隐式this
  只能直接访问静态变量,不能直接访问实例变量
  不需要访问实例变量时,只需对参数操作即可

何时用静态方法,何时用非静态方法:

  静态方法,只与参数相关,与实例变量有关
  Arrays.sort(arr);
  Math.random();
  Math.sqrt(25);

 

何时用静态代码块:
一般用于加载静态资源(图片、音频、视频)

static{
     //静态代码块  
}

final关键字

final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:

  • 声明类:

    final class 类名 {//类体}
  • 声明方法:

    修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
  • Java中常量的设置:

    public static final 数据类型 变量名; 

:实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final

 

abstract

1.抽象方法:由abstract修饰
  只有方法的定义,没有方法体的
2.抽象类:由abstract修饰
  可以包含抽象方法,也可以包含普通方法
3.包含抽象方法的类,必须是抽象类
  类中没有抽象方法,也可以将类声明为抽象类
4.抽象类不能被实例化 Shape s = new Shape();//错误
5.抽象类一般需要被继承:
  1)子类也声明为抽象类
  2)子类重写抽象类中所有抽象方法---首选
6.抽象类的意义:
  1)封装子类公用的成员  为子类提供一个公共的类型
  2)定义抽象方法,由子类来做不同的实现,但入口(方法名)是一样的

abstract class Shape{   //抽象类(不完整)
   int c;   //周长
   abstract double area();  //抽象方法(不完整)
}
class Square extends Shape{   //方形类
   Square(double c){
      this.c = c;
   }
   double area(){  //重写
      return 0.0625*c*c;
   }
}
class Circle extends Shape{   //圆形
   Circle(double c){
      this.c = c;
   }
   double area(){  //重写
      return 0.0796*c*c;
   }
}

  

interface:

1.接口就是一个标准、一个规范
2.接口中只能包含常量和抽象方法
3.接口不能被实例化
  接口 引用 = new 实现类(); //向上造型
4.类实现接口,必须将所有抽象方法都实现
5.类可以实现多个接口,用逗号分隔
  若类又继承父类又实现接口,需先继承后实现
6.接口与接口之间可以继承

接口与类相似点:

  • 一个接口可以有多个方法。
  • 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
  • 接口的字节码文件保存在 .class 结尾的文件中。
  • 接口相应的字节码文件必须在与包名称相匹配的目录结构中。

接口与类的区别:

  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法。
  • 接口不能包含成员变量,除了 static 和 final 变量。
  • 接口不是被类继承了,而是要被类实现。
  • 接口支持多继承。

抽象类和接口的区别

  • 1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  • 2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  • 3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  • 4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

接口特性

  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
interface 接口名称 [extends 其他的类名] {
        // 声明变量
        // 抽象方法
}

接口有以下特性:

  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
  • 接口中的方法都是公有的。
  • 接口中的方法默认带有修饰符 public abstract 常量默认带有修饰符 public static final

 

接口的实现

当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。

类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。

实现一个接口的语法,可以使用这个公式:

...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...

interface Animal {
   public void eat();
   public void travel();
}

  

 

public class MammalInt implements Animal{
 
   public void eat(){
      System.out.println("Mammal eats");
   }
 
   public void travel(){
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
      return 0;
   }
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}

  

伪代码:

想开一个工商银行(对象)
工商银行类---------遵守标准(工行接口)

1.制定标准---接口
  interface UnionPay{   //银联接口
     void 存钱();
     void 取钱();
     void 改密码();
     void 查余额();
  }
  interface ICBC extends UnionPay{   //工行接口
     void 在线支付();
  }
  interface ABC extends UnionPay{    //农行接口
     void 支付电话费();
  }
2.遵守标准----类
  class ICBCImpl implements ICBC{  //工行类
     public void 存钱(){}
     public void 取钱(){}
     public void 改密码(){}
     public void 查余额(){}
     public void 在线支付(){}
     
  }
  class ABCImpl implements ABC{    //农行类
     public void 存钱(){}
     public void 取钱(){}
     public void 改密码(){}
     public void 查余额(){}
     public void 支付电话费(){}
  }
3.main(){
     ICBCImpl icbc1 = new ICBCImpl();//开了1个工行
     icbc1.存钱()/取钱()/改密码()/查余额()/在线支付()

     ABCImpl abc1 = new ABCImpl();

     ICBC i = new ICBCImpl(); //向上造型
  }

  

 

重写接口中声明的方法时,需要注意以下规则:

  • 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
  • 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
  • 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。

在实现接口的时候,也要注意一些规则:

  • 一个类可以同时实现多个接口。
  • 一个类只能继承一个类,但是能实现多个接口。
  • 一个接口能继承另一个接口,这和类之间的继承比较相似。

接口的继承

一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。

// 文件名: Sports.java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}
 
// 文件名: Football.java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}
 
// 文件名: Hockey.java
public interface Hockey extends Sports
{
   public void homeGoalScored();
   public void visitingGoalScored();
   public void endOfPeriod(int period);
   public void overtimePeriod(int ot);
}

  

Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。

相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。

 

接口的多继承

在Java中,类的多继承是不合法,但接口允许多继承。

在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。 如下所示:

public interface Hockey extends Sports, Event

以上的程序片段是合法定义的子接口,与类不同的是,接口允许多继承,而 Sports及 Event 可能定义或是继承相同的方法

 

 

标记接口

最常用的继承接口是没有包含任何方法的接口。

标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。

标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。

例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义如下:

package java.util; public interface EventListener {}

没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的:

  • 建立一个公共的父接口:

    正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。

  • 向一个类添加数据类型:

    这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。

 

什么时候使用抽象类和接口

  • 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
  • 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
  • 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

在 JDK1.8,允许我们给接口添加两种非抽象的方法实现:

  1、默认方法,添加 default 修饰即可;

  2、静态方法,使用 static 修饰;示例如下:

interface Test{
    //这个是默认方法
    default String get(String aa){
        System.out.println("我是jdk1.8默认实现方法...");
        return "";
    }   
    //这个是静态方法    
    static void staticmethod(){
        System.out.println("我是静态方法");
    }
}

  

posted @ 2018-06-14 16:45  Zbuter  阅读(434)  评论(0编辑  收藏  举报