02 JAVA 对象

一天可以new无数个对象,可是老妈还在让我找对象。。。


面向对象的三个基本特点:1. 封装性 2. 继承 3. 多态

易于扩展和维护,封装性好,复用性高

一、面向过程 VS 面向对象

(就喜欢紫色)

面向过程完成事情的步骤,我们一个一个方法实现步骤,然后依次调用,而面向对象是使用某些对象

面向对象优点:

- 我们不需要知道某些方法是如何构建的,封装性好

- 易于管理

面向对象缺点:执行效率

例1:做菜

- 过程

1. 洗菜 2. 放油热锅 3. 炒菜

用户是个厨师,知道所有的步骤

- 对象

厨师对象,有做菜的动态属性

用户是个食客,通知厨师做菜即可

例2:某个游戏的过程(奇葩的游戏,每次玩家执行动作之前都跳一下~不要问我是什么游戏)

玩家1输入

jump()

action(参数)

玩家2输入

jump()

action(参数)

...n个玩家...

判断

返回第一步

此时,我们想要给某个jump()方法添加一个参数(这里不关心参数哪里来的)

- 过程

想给jump()加入一个参数height,此时程序里面所有用到该jump()方法的地方都要修改

- 对象

后台对象b

玩家1输入

b.implement(参数)

玩家2输入

b.implement(参数)

...n个玩家...

判断

返回第一步

1. 技能类Skill,我们需要修改相关的动态属性jump()设定跳高度限制->jump(参数1)

2. 对于后台类

Skill s = new Skill

implement(参数){

获得输入

s.jump()-》s.jump(参数1)

s.action(参数)

}

例3:一个人可以养一只宠物,主人一逗它,它就叫

- 过程

主人逗它,判断宠物类型,宠物叫,但是不同的主人可能养了不同的宠物,猫是喵喵叫,狗是汪汪叫,小鸟是唧唧喳喳叫......我们很难一下子把所有的宠物可能都列出来(对于面向过程,我们需要添加方法,然后修改逻辑判断)

- 对象

动物对象

人对象

人调用动物的叫方法,如果是猫,我们可以创建猫子类,并重写自己的叫方法,不需要修改其他地方的代码

二、对象

对象利用计算机语言对问题域中事务进行描述,类用来描述对象的一个抽象的概念,类可以看作是对象的模板,对象可以看成该类的一个具体实例

- 属性(静态属性)

- 方法(动态属性)


三、类之间的关系

- 关联

这是最弱的一种关系(一个类中的方法参数是另一个类),比如”使用“,人使用车


- 继承

子类拥有父类的属性,什么是什么的一种,JAVA只允许单继承(每一个类只能有一个父类,但一个父类可以有多个子类),多继承可以依靠接口实现


- 聚合

组合 VS 聚集

聚合表示了整体和部分的关系,而根据这种关系的松紧耦合又分为了聚集和组合,组合的每一个部分都是必不可少的,就像人不能没有大脑,而鸟群可以少了一只鸟

- 实现

实现接口,不同的对象对某个方法有不同的实现方式


- 多态



对象都有对外服务的接口,通过继承可以复用,对象隐藏内部服务的实现通过聚合可以复用。组件时比对象更高层次上的复用,相当于好多对象,过程的组合

四、类的定义

【修饰符】class 类名{

成员变量

方法

}

修饰符: public, protected, private, 缺省

成员变量(注意它与局部变量有初始化的区别),它的作用域是整个类,注意类中非static成员变量或者方法不能用在static的方法中,因为static的类成员或者方法是针对所有该类所有对象的,而非static的类成员或方法是针对某个对象的。只有实例化类时,非静态的成员才被初始化,但是我们可以直接调用静态方法,此时如果方法内有非静态成员变量就会出错~

http://blog.sina.com.cn/s/blog_411fed0c0102vh5x.html

静态方法的内存空间是在加载到内存后就被分配到的,而不是等到调用的时候才给分配。静态方法被加载到了内存,分配了空间,无论你是否使用,它就在那里,有且只有一个就它自己。无论多少个线程调用,都是调用的它自己就那么一个。
不同通过类的对象进行调用的方法,那种方法初始化类的对象的时候才被分配空间。而且java有垃圾回收机制,跑出作用域之后它所占的内存就会被回收。

调用非static方法

static void m(Object obj) {

obj.nonStaticM();

}


五、引用

引用类型一般占用两字节(虚拟的物理地址)


code seg: 类,方法

data seg: 静态数据和方法,字符串

stack: 执行过程中的临时变量

heap: 实例,不同的实例可能是不同的大小,因为成员变量值可能是不同的,所以不能实现分配大小

六、构造方法

- 初始化对象的函数,new创建实例的时候调用

- 名字和类同名

- 没有返回值

- 如果没有构造方法,编译器自动添加:

类名(){}

- 但是一旦一个类定义了一个构造方法,系统就不会自动添加

七、命名规则

- 类名首字母要大写,文件名与public类名相同

- 变量名和方法名要小写

- 运用驼峰标识,如furColor

八、内存解析

注意一个内存块数据,没有任何引用指向它的时候的时候就会被自动回收

class BirthDate {
    private int day;
    private int month;
    private int year;
    
    public BirthDate(int d, int m, int y) {
        day = d; 
        month = m; 
        year = y;
    }
    
    public void setDay(int d) {
    	day = d;
  	}
  	
    public void setMonth(int m) {
    	month = m;
    }
    
    public void setYear(int y) {
    	year = y;
    }
    
    public int getDay() {
    	return day;
    }
    
    public int getMonth() {
    	return month;
    }
    
    public int getYear() {
    	return year;
    }
    
    public void display() {
    	System.out.println
        (day + " - " + month + " - " + year);
    }
}


public class Test{
    public static void main(String args[]){
        Test test = new Test();
        int date = 9;
        BirthDate d1= new BirthDate(7,7,1970);
        BirthDate d2= new BirthDate(1,1,2000);    
        test.change1(date);
        test.change2(d1);
        test.change3(d2);
        System.out.println("date=" + date);
        d1.display();
        d2.display();
    }
    
    public void change1(int i){
    	i = 1234;
    }
    
    public void change2(BirthDate b) {
    	b = new BirthDate(22,2,2004);
    }
    
    public void change3(BirthDate b) {
    	b.setDay(22);
    }
}

一个内存块,除了this对自身的引用外,再无其他的引用指向它时~图中x表示临时的~


class Point {
    private double x;
    private double y;
    Point(double x1, double y1) { 
    	x = x1; 
    	y = y1;
    }
    public double getX() { return x; }
    public double getY() { return y; }
    public void setX(double i) { x = i; }
    public void setY(double i) { y = i; }
}

class Circle {
    private Point o;
    private double radius;
    Circle(Point p, double r) {
    	o = p; 
    	radius = r;
    }
    Circle(double r) {
        o = new Point(0.0, 0.0);
        radius = r;
    }
    
    boolean contains(Point p) {
    	double x = p.getX() - o.getX();
    	double y = p.getY() - o.getY();
    	if(x*x + y*y > radius * radius) return false;
    	else return true;
    }
    
    
    public void setO(double x, double y) {
        o.setX(x); 
        o.setY(y);
    }
    public Point getO() { return o; }
    public double getRadius() { return radius;}
    public void setRadius(double r) { radius = r;}
    public double area() { 
        return 3.14 * radius * radius;
    }
}

public class TestCircle {
    public static void main(String args[]) {
        Circle c1 = new Circle(new Point(1.0,2.0), 2.0);
        Circle c2 = new Circle(5.0);
        System.out.println("c1:("+c1.getO().getX()+","
            +c1.getO().getY()+"),"+c1.getRadius());
        System.out.println("c2:("+c2.getO().getX()
            +","+c2.getO().getY()+"),"+c2.getRadius());
        System.out.println("c1 area = "+c1.area());
        System.out.println("c1 area = "+c2.area());
        c1.setO(5,6);
        c2.setRadius(9.0);
        System.out.println("c1:("+c1.getO().getX()+","
            +c1.getO().getY()+"),"+c1.getRadius());
        System.out.println("c2:("+c2.getO().getX()+","
            +c2.getO().getY()+"),"+c2.getRadius());
        System.out.println("c1 area = "+c1.area());
        System.out.println("c1 area = "+c2.area());
        
        Point p1 = new Point(5.2, 6.3);
        System.out.println(c1.contains(p1));
        System.out.println(c1.contains(new Point(10.0,9.0)));
        
    }
}


九、方法重载overload

我们可以在一个类中定义相同名字的方法(但是参数是不同的,比如数据类型,参数个数),调用时,会根据不同的参数表选择对应的方法,构造方法也可以被重载

十、关键字this

this指向使用当前方法的对象,this可以被看做一个变量,是当前对象的引用,每个对象中都存在一个this


public class Leaf {
	int i = 1;
	
	Leaf(int i) {
		this.i = i;
	}
	
	Leaf increament() {
		i++;
		return this;
	}
	
	void print() {
			System.out.println("i="+i);
	}
	
	public static void main(String args[]){
		Leaf leaf = new Leaf(100);
		leaf.increament().increament().print();
	}
}
结果是:

i=102



十一、关键字static

static类型的数据,不需要创建实例就已经在内存里面了

static方法和数据都在数据区内

- 静态成员变量(存放在数据区),为该类的公共变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份

- 静态方法,不针对某个对象调用,所以在static方法中不可访问非static成员,可以通过对象引用或者类名访问静态成员

http://blog.youkuaiyun.com/peterwin1987/article/details/7571808

static方法就是类装载的时候就加载进来了,而非static方法是调用的时候才装载到内存

http://zhidao.baidu.com/question/1817880738458676908.html

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 arg[]){

        Cat.sid = 100;
        Cat mimi = new Cat("mimi");
        mimi.sid = 2000;
        Cat pipi = new Cat("pipi");
        mimi.info(); 
        pipi.info();
    }
}


十二、package和import

package: 提供类的多重命名空间,不同的包可以含有相同名字的类,包路径规则通常是把公司域名倒过来比如net.princeton.包名,此时我们需要将net的上一层目录放入classpath中。如果程序没有package语句,则默认指定为无名包


- 编译出来的class文件必须位于正确的目录下面,并在classpath中添加该目录

- 如果想要在另一个类用这个包里的类,必须把名字写全,或者import(".",包)

- 不要把源代码放到放class的包中,可能会出错

Eclipse为不同的项目设置不同的classpath,不共享class文件


一些主要的包:

目录jdk/jre/lib/rt.jar/java

java.lang 包含一些JAVA的核心类,如String, Math, Integer, System, Thread等,默认引入

java.awt 与界面GUI相关的类

java.applet applet运行所需的一些类

java.net 网络相关的操作的类

java.io 提供多种输入、输出功能的类

java.util 一些实用的工具类,如定义系统特性,使用与日期日历相关的函数

classpath里面的jar包目录包含了jar包的名字

jar -cvf xx.jar *.* 解压压缩包

十三、继承和权限

关键字extends

子类拥有基类所有的成员变量和方法,只支持单继承,一个子类只能有一个基类,但一个基类可以有多个子类

修饰符有4个权限:public, private, protected, 缺省

class只能缺省或被public修饰


对于default和protected来说,其实应该这样讲,不同包中的类不能继承default类,而且不同包中的子类不能访问父类的default成员

十四、重写override

对父类方法进行重写(必须有相同的名称,参数和返回类型),重写方法不能使用比被重写的方法采用更严格的权限,里氏替换原则,子类对象可以被当成父类对象使用

十五、关键字super

使用super来引用父类的this

对于子类的构造方法,必须使用父类的构造方法,换言之,我们创建子类的同时创建了父类,我们可以使用super来实现,this可以用来调用本类的另外构造方法。如果子类没有调用基类的构造方法,系统默认调用基类的无参数构造方法,但是如果父类没有无参构造函数,则出错。super都写在第一行

多看例子就懂了吧~

class Parent {
	public int value;
	public void f() {
		value = 100;
		System.out.println("Parent: "+value);
	}
}

class Child extends Parent {
	public int value;
	public void f() {
		super.f();
		value = 200;
		System.out.println("Child: "+value);
		System.out.println("parent: "+super.value);
	}
}

public class TestSuper {
	public static void main(String args[]) {
		Child c = new Child();
		c.f();
	}
}

结果:

Parent: 100

Child: 200

parent: 100


class A {
	A() {
		print("A()");
	}
	
	protected void print(String a) {
		System.out.println(a);
	}
	
	public void f() {
		print("A:f()");
	}
}

class B extends A {
	B() {
		print("B()");
	}
	
	public void f() {
		print("B:f()");
	}
}

public class TestSuper2 {
	public static void main(String[] args) {
		B b = new B();
		b.f();
	}
}


结果:

A()

B()

B:f()

class Person1 {
	private String name;
	private String location;
	
	Person1(String name) {
		this.name = name;
		location = "Beijing" ;
	}
	
	Person1(String name, String location) {
		this.name = name;
		this.location = location;
	}
	
	public String info() {
		return "name: "+name+" location: "+location;
	}
}

class Student1 extends Person1 {
	private String school;
	Student1(String name, String school) {
		this(name, "beijing", school);
	}
	
	Student1(String name, String location, String school) {
		super(name, location);
		this.school = school;
	}
	
	public String info() {
		return super.info()+" school: "+school;
	}
}

public class TestSuper3 {
	public static void main(String[] args) {
		Student1 sd =new Student1("Mike", "IC");
		System.out.println(sd.info());
	}
}
结果:

name: Mike location: beijing school: IC

十六、大基类Object

Object是所有类的基类,当我们没写extends的时候,就默认继承Object

属性Class, 方法clone,getClass,toString,hashcode,equals,finalize等

十七、hashcode

java hash好白痴的,因为可能会发生两个不同内容对应同一个key的可能

十八、toString

Object类定义了一个public String toString()方法,返回String类型,描述当前对象有关信息,当String与其他类型进行数据连接时会自动调用这个函数,如System.out.println("info"+person),可以根据需要在子类中重写

toString(对象)的结果是类名@hash值

十九、equals方法

Object类还提供了public boolean equals(Object obj)方法,判断两个对象是否相等,默认是根据引用对象是否指向同一个来判断(与==作用相同),但是我们可以重写来根据对象的内容,而不根据引用来判断:

if(obj==null) return false;

else{

if(obj instanceof Cat){

Cat c=(Cat)obj;

if(c.color==this.color……){

return true;

}

}

}

return false;

public class TestEqual {
	public static void main(String[] args) {
		Integer i1 = new Integer(1);
		Integer i2 = new Integer(1);
		System.out.println(i1 == i2);
		System.out.println(i1.equals(i2));
		Mao m1 = new Mao("A", "A");
		Mao m2 = new Mao("A", "A");
		System.out.println(m1 == m2);
		System.out.println(m1.equals(m2));
	}
}

class Mao {
  String name;
  String color;
  Mao(String n,String c){
    name = n; color = c;
  }
  

结果:

false

true

false

true

二十、对象转型casting
一个基类的引用类型变量可以指向其子类的对象,一个基类的引用不可以访问其子类对象新增加的成员,也就是比如别人把狗当成动物传给你,你只能把他当做动物,我们可以使用“变量 instanceof 类名”来判断该引用型变量所指向的对象是否属于该类或该类的子类
- upcasting 将子类对象当基类对象使用
- downcasting 将基类当子类对象使用,例如cat(obj)
class Animal1 {
	public String name;
	
	Animal1(String name) {
		this.name =  name;
	}
}
class Cat1 extends Animal1{
	public String color;
	
	Cat1(String name, String color) {
		super(name);
		this.color = color;
	}
	
	void f(){
		System.out.println("喵喵喵~");
	}
}

public class TestCasting {
	public static void main(String args[]) {
		String name = "Shirley", color = "Brown";
		String name1 = "Bobby", color1 = "Black";
		Cat1 c1 = new Cat1(name,color);
		Animal1 c2 = new Cat1(name1,color1); //upcasting
		
		System.out.println("cat1, name: "+c1.name+" color: "+c1.color);
		c1.f();
		//System.out.print("cat2, name: "+c2.name+" color: "+c2.color);不能执行,因为父类不能调用子类的成员变量color
		//c2.f();不能执行,因为是Animal1引用类型变量,不能调用子类的成员
		
		//downcasting
		if (c2 instanceof Cat1) {
			Cat1 c2_2 = (Cat1) c2;
			System.out.println("cat2, name: "+c2_2.name+" color: "+c2_2.color);
			c2_2.f();
		}
	}
}




二十二、动态绑定

动态绑定(多态,池绑定)

执行期间绑定,根据实际类调用相应的方法,而不是编译期间绑定,实现条件:

- 继承

- 重写

- 父类引用指向子类对象

class Animal2 {
	public void enjoy() {
		System.out.println("叫");
	}
}

class Person2 {
	String name;
	Animal2 a2;
	Person2(Animal2 a2, String name) {
		this.a2 = a2;
		this.name = name;
	}
	void petEnjoy(){
		a2.enjoy();
	}
}

class Bird extends Animal2 {
	public void enjoy() {
		System.out.println("唧唧喳喳");
	}
}

class Dog1 extends Animal2 {
	public void enjoy() {
		System.out.println("汪汪汪");
	}
}
public class TestPool {
	public static void main(String args[]) {
		Animal2 b = new Bird();
		Animal2 d = new Dog1();
		Person2 p1 =  new Person2(b, "Amy");
		Person2 p2 =  new Person2(d, "Jack");
		System.out.print(p1.name+"'s pet ");
		p1.petEnjoy();
		System.out.print(p2.name+"'s pet ");
		p2.petEnjoy();
	}
}

结果:

Amy's pet 唧唧喳喳

Jack's pet 汪汪汪

前面学过,父类不能调用子类的方法,但是看下多态,当子类中有相同名字和参数的方法时,就调用子类的


二十三、抽象类

关键字abstract

看下动态绑定的例子,有没有发现其实那个Animal的enjoy方法根本不需要实现,此时抽象方法就被引入了,抽象方法的拥有类必须为抽象类(但是抽象类除了抽象方法还可以拥有普通的成员变量和普通的方法),抽象方法只需要被声明而不实现,所以抽象类必须被继承,方法必须被重写,抽象类不能实例化,抽象可以继承抽象,注意抽象类依然保持单继承性。

二十四、关键字final

final变量的值不能被改变,方法不能被重写,类不能被继承,这样可以保护数据。方法参数如果是final类型的话,这个参数在方法中不能被改变,如果参数是个引用,则该引用不能指向别的对象,但是其实对象内的值还是可以被修改的~

public class TestFinal {
	void execute(int s){
		s = s+3; 
		System.out.println(s);
	}
	
	public static void main(String args[]) {
		final int ii = 3;
		testFinal tf = new testFinal();
		tf.execute(ii);
	}
}
结果是:6

因为我们只是把ii的值3传给对象s,而不是s就是ii对象,此时将execute参数变成final int s,此时s就不能改变

String, Math和一些基础类型包装类都是final类型的

二十五、接口
关键字interface, implements

接口是对实物的属性和行为更高层次的抽象,是抽象方法和常量值的定义的集合,从本质上看,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。多个无关的类可以实现同一个接口,而且一个类可以实现多个接口,实现多态性,接口可以继承其他的接口,添加新的属性和抽象方法,采取对修改关闭,对扩展开放得开闭原则

接口中的属性默认都是public static final的,为什么??

- 首先我们定义接口属性,希望别人能用上,是所有类都可以拥有的属性,如果具体实现类不能使用该属性,不就没有意义了嘛(同理,接口和接口方法也都是默认public)

- static的话,所有类共有的特性,如果非static的话,只有类创建实例的时候才能拥有这些方法,那么就不能被继承啦,并且一个类可以继承多个接口,如果出现重名不好区分(

public Interface Interface1 {

void getDesc();

}

public Interface Interface2 {

void getDesc();

}

public class TestInterface implements Interface1, Interface2 {

void getDesc(); //因为getDesc是静态的,不会出错

}


但是如果A接口底下有一个double getMoney()方法,而B接口下有一个void getMoney()的方法,此时一个类同时实现这两个接口,就不好办了)

http://bbs.itheima.com/thread-162971-1-1.html

- 接口的成员不能修改,如果不是final的话,子类就可以修改,不符合开闭原则 ,就想我们有一个模板,希望后面可以添加功能,并不修改本来的功能

interface Singer {
	void sing();
}

interface Painter {
	void paint();
}

class Student3 implements Singer {
	public void sing() {
		System.out.println("sing3");
	}
}

class Student4 implements Singer, Painter {
	public void paint() {
		System.out.println("paint4");
	}
	public void sing() {
		System.out.println("sing4");
	}
}

public class TestInterface {
	public static void main(String args[]) { 
		Singer s1 = new Student3();
		s1.sing();
		Singer s2 = new Student4();
		s2.sing();
		//s4.paint(); 执行错误
		Painter p = (Painter)s2;
		//p.sing(); 执行错误
		p.paint(); 
	}
}




记下一些MAC快捷键:

cmd+m 

cmd+n

cmd+f

shift+cmd+g

cmd+tab


Reference:

1. 马士兵JAVA基础视频

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值