疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java基础类与对象


 

   

  类与对象

  概念贴士:

  1.  类必须先定义了才能使用。类是创建对象的模板,创建对象也叫类的实例化。

  2.  在Java中,使用new关键字来创建对象,一般有一下3个步骤:

  1)声 明:声明一个对象,包括对象名称和对象类型。

  2)实例化:使用关键字new创建一个对象。

  3)初始化:使用new创建对象时,会调用构造方法初始化对象。

  3.  在类实例化的过程中自动执行的方法叫做构造方法,它不需要手动调用。构造方法可以在类实例化的过程中完成一些初始化的工作。构造方法的名称必须与类的名称相同,并且没有返回值。每个类都有构造方法,如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认的构造方法。

  4.  Java通过修饰符来控制类、属性和方法的访问权限和其他功能,通常放在语句的最前端。

  5.  Java的修饰符很多,分为访问修饰符和非访问修饰符。其中访问修饰符也叫访问控制符,是指能够控制类、成员变量、方法的使用权限的关键字。  在面向对象编程中,访问控制符是一个很重要的概念,可以使用它来保护对类、变量、方法和控制方法的访问。

  6.  Java支持4种不同的访问权限:

  1)public      共有的,对所有类可见

  2)protected    受保护的,对同一包内的类和所有子类可见

  3)private      私有的,在同一类内可见

  4)默认的      在同一包内可见,默认不使用任何修饰符

  6.1  public:公有的

  被声明为public的类、方法、构造方法行业接口能够被任何其他类访问。如果几个相互访问的public类分布在不同的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被子类继承。

  例子:public static void main(String[] arguments){}

  PS:Java程序main()方法必须是设置成公有的。

  6.2  protected:受保护的

  被声明为protected的变量、方法和构造方法能够被同一包中的任意其他类访问,也能够被不同包中的子类访问。protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。

  例子:

  复制代码

  1 public class Dog{

  2 protected void bark(){

  3 System.out.println("汪汪,不要过来!");

  4 }

  5 }

  6

  7 class Teddy extends Dog{ //泰迪

  8 protected void bark(){

  9 System.out.println("汪汪,我好怕,不要跟着我!");

  10 }

  11 }

  复制代码

  PS:如果把bark()方法声明为private,那么除了Dog之外的类将不能访问该方法。如果把bark()方法声明为public,那么所有的类都能够访问该方法。如果只想让该方法对其所在类的子类可见,则将该方法声明为protected即可。

  6.3  private:私有的

  私有访问修饰符是最严格的访问控制级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。  声明为私有访问类型的变量只能通过类中公共的getter/setter方法被外部类访问。private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。

  例子:

  复制代码

  1 public class Dog{

  2 private String name;

  3 private int age;

  4 public String getName(){

  5 return name;

  6 }

  7 public void setName(String name){

  8 this.name=name;

  9 }

  10 public int getAge(){

  11 return age;

  12 }

  13 public void setAge(int age){

  14 this.age=age;

  15 }

  16 }

  复制代码

  PS:程序中,Dog类中的name、age变量为私有变量,所以其他类不能直接得到和设置该变量的值。为了使其他类能够操作该变量,程序中定义了两对public方法,getName()/setName()和getAge()/setAge(),用来获取和设置私有变量的值。

  PS:this是Java中的一个关键字,在类中定义访问私有变量的方法,习惯上是这样命名的:在变量名称前面添加get或者set,并将变量的首字母大写。上述两对方法由于经常使用,也有特定的称呼,称为getter和setter方法。

  6.4  默认的:不使用任何关键字

  不适用任何修饰符声明的属性和方法,对同一个包内的类是常见的。接口的变量都隐式声明为public static final(final为非访问修饰符之一),而接口里的方法默认情况下访问权限为public。

  6.5  访问控制符使用小总结:

  访问控制符可以令我们便于控制代码的权限。

  1)当需要让自己编写的类被所有的其他类访问时,就可以将类的访问控制符声明为public。

  2)当需要让自己的类只能被自己的包中的类访问时,就可以省略访问控制符。

  3)当需要控制一个类中的成员数据时,可以将这个类中的成员数据访问控制符设置为public、protected或者省略。

  2. 方法继承的规则。

  1)父类中声明为public的方法在子类中也必须为public。

  2)父类中声明为protected的方法在子类中要么声明为protected,要么声明为public,不能声明为private。

  3)父类中默认修饰符声明的方法,能够在子类中声明为private。

  4)父类中声明为private的方法,不能被继承。

  7.  在Java中,变量的作用域分为4个级别,即类级、对象实例级、方法级和块级。(详见实例3-4)

  1)类级变量又称为全局级变量或者静态变量,需要使用static关键字修饰,类级变量在类定义后就已经存在,占用内存空间,可以通过类名来访问,不需要实例化。

  2)对象实例级变量就是成员变量,实例化后才会分配内存空间,才能访问。

  3)方法级变量是在方法内部定义的变量,是局部变量。

  4)块级变量是定义在一个块内部的变量,变量的生存周期就是这个块,出了这个块则变量消失,如if、for语句的块。块是指由大括号(花括号)包围的代码。

  8.  在Java中,this可以在类里引用这个类的属性和方法。this关键字用来表示当前对象本身,或当前类的一个实例,通过this关键字可以调用本对象的所有方法和属性。(详见实例3-5)

  9.  成员变量与方法内部的变量重名时,希望在方法内部调用成员变量,可以通过使用this关键字区分同名变量。(详见实例3-6)

  10.  在构造函数中通过this引用来调用另一个构造函数,也就是相当于调用本类的其他构造方法,它必须作为构造方法的第一句(即作为方法名初始化对象)。(详见实例3-7)

  11.  需要在某些完全分离的类中调用一个方法,并将当前对象的一个引用作为参数传递时,可以使用this关键字,作为参数传递。(详见实例3-8)

  12.  在Java中

  ,同一个类中的多个方法可以有相同的名字,但参数列表不同,这被称为方法重载(method overloading)。重载是面向对象的一个基本特性。  参数列表又叫参数签名,包括参数的类型,参数的个数与参数的顺序,只要有一个不同就叫做参数列表不同。(详见实例3-9)

  13.  1.重载说明:

  1)参数列表不同包括:个数不同、类型不同和顺序不同。

  2)仅参数变量名称不同是不可以的(毕竟那只是形参)。

  3)与成员方法一样,构造方法也可以重载。

  4)声明为final的方法不能被重载(感兴趣可以查询final这个非访问修饰符)。

  5)声明为static的方法不能被重载,但是能够被再次声明。

  2.方法的重载规则:

  1)方法名称必须相同。

  2)参数列表必须不同。

  3)方法的返回类型可以不同,也可以相同。

  4)仅仅返回类型不同不足以成为方法的重载。

  3.方法重载的实现:方法名称相同时,编译器会根据调用方法的参数个数、参数类型等逐个去匹配,以选择对应的方法,如果匹配失败,则编译器报错,这叫重载分辨。

  14.  Java为每种基本数据类型分别设计了对应的类,实现数据间类型转化,这些类被称之为包装类(Wrapper Classes)。

  15.  封装就是将属性私有化,提供公有的方法访问私有的属性。其实现步骤如下:

  1)修改属性的可见性限制对属性的访问。

  2)为每个属性创建一对赋值方法和取值方法,用于对这些属性的访问。

  3)在赋值和取值方法中,加入对属性的存取限制。

  16.  为了实现良好的封装性,通常将类的成员变量声明为private,再通过public的方法对这个变量进行访问。对一个变量的操作,一般是读取和赋值操作,下面分别定义两个方法来实现这两种操作,一个是getXxx()方法(Xxx表示要访问的成员变量的名字),用来读取这个成员变量操作;另外一个是setXxx()方法,用来对这个成员变量赋值。(详见实例3-10)

  代码解释:

  实例3-1

  复制代码

  1 package duke.example.ch3;

  2

  3 public class Dog{

  4 String name; //名字

  5 int age; //年龄

  6

  7 void bark(){ //汪汪叫

  8 System.out println("汪汪,不要过来");

  9 }

  10

  11 void hungry(){ //饥饿

  12 System.out.println("主任,我饿了");

  13 }

  14 }

  复制代码

  代码说明: 代码行.3中 public是类的修饰符,表明该类是公共类,可以被其他类访问。class是定义类的关键字,Dog是类名称。

  代码行.4-5中 name、age是类的成员变量,也叫属性。

  代码行.7-9中 bark()是类中的函数,也叫方法,即定义犬吠这个方法。

  代码行.11-13中 hungry()是类中的函数,也叫方法。

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

  局部变量:在方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在这个方法中,方法结束后,变量就会自动销毁。

  成员变量:在类中、方法体之外定义的变量。这种变量在创建变量的时候实例化(分配内存)。成员变量可以被类中的方法和特定类的语句访问。

  类 变 量 :也是在类中、方法体之外定义的变量,但必须声明为static类型。static也是修饰符的一种。

  实例3-2

  复制代码

  1 package duke.example.ch3;

  2

  3 public class Dog{

  4 String name; //名字

  5 int age; //年龄

  6

  7 Dog(String name,int age){ //构造方法,没有返回值

  8 this.name=name;

  9 this.age=age;

  10 System.out.println(name+“感谢主人天天带我玩耍!”);

  11 }

  12

  13 void bark(){ //汪汪叫

  14 System.out println("汪汪,不要过来");

  15 }

  16

  17 void hungry(){ //饥饿

  18 System.out.println("主任,我饿了");

  19 }

  20

  21 public static void main(String[] args){

  22 //创建对象时传递的参数要与构造方法参数列表对应

  23 Dog myDog=new Dog("卡拉",3);

  24 System.out.println("我是一只小狗,我的名字叫"+name+",我"+age+"岁了!");

  25 }

  26 }

  复制代码

  输出结果:

  卡拉感谢主人天天带我玩耍!

  我是一只小狗,我的名字叫卡拉,我3岁了!

  代码说明: 代码行.7-9中 定义包含两个参数name和age的构造函数,构造方法的名称必须与类的名称Dog相同。构造方法不能有返回值,因为没有变量来接收返回值。

  代码行.23中 构造方法不能被显示调用,在类Dog实例化的过程中自动执行了。

  代码执行顺序:

  1)先运行到代码行.21。这是程序的入口。

  2)然后运行代码行.23。这里要创建一个Dog,就要调用Dog的构造方法。

  3)运行到代码行.7。注意接下来并不是运行代码行.8,初始化一个类,必须先初始化他的属性。

  4)因此运行到代码行.4。然后是代码行.5。

  5)属性初始化后,才回到构造方法,执行里面的代码,也就是代码行.8-10。

  6)然后是代码行.11。表示创建一个Dog实例完成。

  7)然后回到main()方法中执行代码行.23-24。

  8)最后是代码行.25。main()方法执行完毕。

  书上说作为程序员,应该知道程序的基本运行过程,否则不利于编写代码与进步,其实这是有道理的。在一个程序中,你看到的深度决定了你编程水平的上限。

  实例3-3

  复制代码

  1 package duke.example.ch3;

  2

  3 public class Dog{

  4 String name; //名字

  5 int age; //年龄

  6

  7 Dog(String name,int age){ //构造方法,没有返回值

  8 this.name=name;

  9 this.age=age;

  10 System.out.println(name+“感谢主人天天带我玩耍!”);

  11 }

  12

  13 void bark(){ //汪汪叫

  14 System.out println("汪汪,不要过来");

  15 }

  16

  17 void hungry(){ //饥饿

  18 System.out.println("主任,我饿了");

  19 }

  20

  21 public static void main(String[] args){

  22 //创建对象时传递的参数要与构造方法参数列表对应

  23 Dog myDog=new Dog("卡拉",3);

  24 //访问成员变量

  25 String name=myDog.name;

  26 int age=myDog.age;

  27 System.out.println("我是一只小狗,我的名字叫"+name+",我"+age+"岁了!");

  28 //访问方法

  29 myDog.bark();

  30 myDog.hungry();

  31 }

  32 }

  复制代码

  输出结果:

  卡拉感谢主人天天带我玩耍!

  我是一只小狗,我的名字叫卡拉,我3岁了!

  汪汪,不要过来!

  主人,我饿了!

  代码说明: 代码行.26-27中 通过点号(.)访问变量name和age。

  代码行.29-30中 通过点号(.)访问成员方法bark()和hungry()。

  实例3-4

  复制代码

  1 package duke.example.ch3;

  2

  3 public class Scope{

  4 public static String name="爪哇岛旅游攻略"; //类级变量

  5 public int i; //对象实例级变量

  6

  7 //属性块,在类初始化属性时候运行

  8 {

  9 int j=2; //块级变量

  10 }

  11

  12 public void test(){

  13 int j=3; //方法级变量

  14 if(j==3){

  15 int k=5;

  16 }

  17 //这里不能访问块级变量,块级变量只能在块内部访问

  18 System.out.println("name="+name+",i="+i+",j="+j);

  19 }

  20

  21 public static void main(String[] args){

  22 //不创建对象,直接通过类名访问类级变量

  23 System.out.println(Scope.name);

  24 //创建对象并访问它的方法

  25 Scope.scope=new Scope();

  26 scope.test();

  27 }

  28 }

  复制代码

  输出结果:

  爪哇岛旅游攻略

  name=爪哇岛旅游攻略,i=0,j=3

  代码说明: 代码行.4中 使用static关键字定义类级字符串变量name。

  代码行.12-19中 定义方法test(),方法内部定义了方法级变量和块级变量。

  PS:  1)方法内部除了能访问方法级的变量,还可以访问类级和实例级的变量。

  2)块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。

  3)方法级和块级的变量必须被显式初始化,否则不能访问。

  实例3-5

  复制代码

  1 package duke.example.ch3

  2

  3 public class ThisDemo1 {

  4 public int x=10;

  5 public int y=15;

  6

  7 public void sum() {

  8 int z=this.x+this.y;

  9 System.out.println("x+y="+z);

  10 }

  11

  12 public static void main(String[] args) {

  13 ThisDemo1 thisdemol=new ThisDemo1();

  14 thisdemo1.sum();

  15 }

  16 }

  复制代码

  输出结果:

  x+y=25

  代码说明: 代码行.4-5中 定义成员变量x和y。

  代码行.8中 通过this点取成员变量。

  PS:上面程序中,thisdemol时ThisDemol类的一个实例,this和thisdemol等价,执行int z=this.x+this.y;,就相当于执行int z=thisdemol.x+thisdemol.y;。

  PS:this只有在类实例化后才有意义。

  实例3-6

  复制代码

  1 package duke.example.ch3;

  2

  3 public class ThisDemo2 {

  4 public String name;

  5 public int age;

  6

  7 public ThisDemo2(String name,int age) {

  8 this.name=name;

  9 this.age=age;

  10 }

  11

  12 public void say() {

  13 System.out.println("网站的名字是"+name+",已经成立了"+age+"年");

  14 }

  15

  16 public static void main(String[] args) {

  17 ThisDemo2 thisdemo2=new ThisDemo2("www.baidu.com",15);

  18 thisdemo2.say();

  19 }

  20 }

  复制代码

  输出结果:

  网站的名字是www.baidu.com,已经成立了15年

  代码说明: 代码行.7-10中 成员变量与方法内部的变量重名时,通过this引用调用成员变量。  形参的作用域是整个方法体,是局部变量。在ThisDemo2(String name,int age)中,形参与成员变量重名,如果不使用this,访问到的就是局部变量name和age,而不是成员变量。

  代码行.12-14中 在say()中没有使用this,因为成员变量的作用域是整个实例,当然也可以加上this。

  eg:System.out.println("网站的名字是"+this.name+",已经成立了"+this.age+"年"):

  PS:Java默认将所有成员变量和成员方法与this关联在一起,因此使用this在某些情况下是多余的。

  实例3-7

  复制代码

  1 package duke.example.ch3;

  2

  3 public class ThisDemo3 {

  4 public String name;

  5 public int age;

  6

  7 public ThisDemo3() {

  8 this("www.baidu.com",15);

  9 }

  10

  11 public ThisDemo3(String name,int age) {

  12 this.name=name;

  13 this.age=age;

  14 }

  15

  16 public void say() {

  17 System.out.println("网站的名字是"+name+",已经成立了"+age+"年");

  18 }

  19

  20 public static void main(String[] args) {

  21 ThisDemo3 thisdemo3=new ThisDemo3();

  22 thisdemo3.say();

  23 }

  24 }

  复制代码

  输出结果:

  网站的名字是www.baidu.com,已经成立了5年

  代码说明: 代码行.7-9中 在构造方法中,this调用另一个构造方法,调用动作必须置于最起始的位置。注意,不能在构造方法以外的任何方法内调用构造方法,在一个构造方法内只能调用一个构造方法。

  PS:上述代码设计方法重载,即Java允许出现多个同名方法,只要参数不同即可。

  实例3-8

  复制代码

  1 package duke.example.ch3;

  2

  3 public class ThisDemo4 {

  4

  5 public static void main(String[] args) {

  6 B b=new B(new A());

  7 }

  8 }

  9

  10 class A {

  11 public A() {

  12 new B(this).print();

  13 }

  14

  15 public void print() {

  16 System.out.println("Hello from A!");

  17 }

  18 }

  19

  20 class B {

  21 A a;

  22

  23 public B(A a) {

  24 this.a=a;

  25 }

  26

  27 public void print() {

  28 a.print();

  29 System.out.println("Hello from B!");

  30 }

  31 }

  复制代码

  输出结果:

  Hello from A!

  Hello from B!

  代码说明: 代码行.12中 匿名对象就是没有名字的对象。如果对象只是用一次,就可以作为匿名对象,代码中new B(this).print();等价于(new B(this)).print();,先通过new B (this)创建一个没有名字的对象,再调用它的方法。

  实例3-9

  复制代码

  1 package duke.example.ch3;

  2

  3 public class Overload {

  4 //一个普通的方法,不带参数的

  5 void test() {

  6 System.out.println("No parameters");

  7 }

  8

  9 //重载上面的方法,并且带了一个整型参数

  10 void test(int a) {

  11 System.out.println("a:"+a);

  12 }

  13

  14 //重载上面的方法,并且带了两个整型参数

  15 void test(int a,int b) {

  16 System.out.println("a and b:"+a+" "+b);

  17 }

  18

  19 //重载上面的方法,并且带了一个双精度参数

  20 double test(double a) {

  21 System.out.println("double a:"+a);

  22 return a*a;

  23 }

  24

  25 public static void main(String[] args) {

  26 Overload overload=new Overload();

  27 overload.test;

  28 overload.test(2);

  29 overload.test(2,3);

  30 overload.test(2,0);

  31 }

  32 }

  复制代码

  输出结果:

  No parameters

  a:2

  a and b:2 3

  double a:2.0

  PS:重载就是在一个类中,有相同的函数名称,但形参不同的函数。重载的结果,可以让一个程序段减少代码和方法的种类。

  实例3-10

  复制代码

  1 package duke.example.ch3;

  2

  3 public class Person {

  4 //封装属性:将属性设置为私有

  5 private String name;

  6 private int age;

  7

  8 public String getName() { //外部通过此方法访问name属性

  9 return name;

  10 }

  11

  12 public void setName(String name) { //该方法是外部赋值私有属性name

  13 this.name=name;

  14 }

  15

  16 public int getAge() { //外部通过此方法访问age属性

  17 return age;

  18 }

  19

  20 public void setAge(int age) { //该方法使外部赋值私有属性age

  21 shis.age=age;

  22 }

  23

  24 void say() { //此方法可以被外部直接调用使用

  25 System.out.println("我叫"+name+",今年"+age+"岁了!");

  26 }

  27

  28 public static void main(String[] args) {

  29 Person person=new Person();    //实例化person类

  30 person.setName("小芳"); //通过开放方法给实例化对象的name属性赋值

  31 person.setAge(22); //通过开放方法给实例化对象的age属性赋值

  32 person.say(); //通过实例化对象的方法

  33 }

  34 }

  复制代码

  输出结果:

  我叫小芳,今年22岁了!

  代码说明: 代码行.5-6中 private是修饰符表示私有化,这就封装了类的属性,封装后外部不能直接使用该属性。

  代码行.7-22中 对外用标准的set/get方法修改/读取属性name和age的值。

  代码行.24中 定义方法say(),该方法可以被外部直接调用使用。

  PS:封装的优点:

  1)隐藏类的实现细节。

  2)让使用者只能通过实现制定好的方法访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作。

  3)便于修改,增强了代码的可维护性。

  总结:这一部分主要谈到了Java的类及其相关基础应用。另外,类的继承和多态是其高阶应用。