02 JAVA 对象
来源:互联网 发布:微信开发团队 知乎 编辑:程序博客网 时间:2024/06/05 12:38
一天可以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.csdn.net/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
二十、对象转型castingclass 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); //upcastingSystem.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引用类型变量,不能调用子类的成员//downcastingif (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基础视频
- [Java] 对象转型-02
- 02 Java面向对象
- 02 JAVA 对象
- Java面向对象02
- java学习-面向对象02
- 面向对象02--java基础
- 02-java对象高级篇
- JAVA面向对象练习02
- Java对象
- Java对象
- java对象
- JAVA-对象
- java对象
- Java 对象
- Java对象
- java对象
- Java 对象
- java对象
- 1067 : 最近公共祖先·二
- HDU 4768 Flyer
- 严重: IOException while loading persisted sessions: java.io.EOFException
- iOS CALayer-实现颜色的渐变和曲线图
- 2012年5月SAT香港真题解析
- 02 JAVA 对象
- JS中&&和||用法
- C语言中逻辑运算符的陷阱
- Java从网络读取图片并保存至本地
- PAT (Advanced Level) 1012. The Best Rank (25) 最佳排名,结构体排序,哈希查询
- No resource found that matches the given name 'android:Widget.Material.ActionButton'
- unity3D的update·函数
- 系统服务-----NotificationManager
- LinearLayout 使用