【java】关于java类和对象,你想知道的在这里!

简介: java类的基本组成 java作为一门面向对象的语言, 类和对象是最重要的概念之一,下面,就让我们来看看java中类的基本结构是怎样的:   一个简单的java类主要可由以下几个部分(要素)组成: 1.

java类的基本组成

java作为一门面向对象的语言, 类和对象是最重要的概念之一,下面,就让我们来看看java中类的基本结构是怎样的:
 
一个简单的java类主要可由以下几个部分(要素)组成:
1.实例变量
2.构造函数 
3.更改器方法
4.访问器方法
 
例如:
class Myclass {
   field1...  // 声明实例变量(实例域)
   field2...  // 声明实例变量(实例域)
   constructor..   // 构造函数
   getMethod1..  // 访问器方法1
   getMethod2..   // 访问器方法2
   setMethod1...  // 更改器方法1
   setMethod2...  // 更改器方法2
}

 

也许你对java类的运用早已了熟于心了,但对结构的细化和分析有助于你进一步的了解
让我们看一下下面这个实例
 
Myclass.java:
public class Myclass {
     private String name;  // 声明实例变量(实例域)
     public Myclass () {   // 构造函数
       name = "尚无名字";
     }
     public String getName () {   // 访问器方法
       return name;
     }
     public void setName (String str) {  // 更改器方法
       name = str;
     }
}

 

Test.java:
public class Test {
   public static void main(String args []) {
     Myclass instance = new Myclass();
     System.out.println(instance.getName());  // 输 出当前的实例变量name的值
     instance.setName("彭湖湾");    // 修改name的值
     System.out.println(instance.getName()); // 再次输 出实例变量name的值
   }
}

 

结果:
尚无名字
彭湖湾

 

 
关于构造函数有几点要注意:
1. 构造函数和类同名
2. 它没有返回值
3. 可以有多个构造函数,允许实现构造函数重载(下面会讲)
 
【注意】没有返回值意味着你不能在构造函数里写return XXX,或者是为方法加上类型如public String Myclass() (具体点说,如果你在构造器里面return一个值会直接导致报错error,而如果你通过public String Myclass的方式加上类型,那么这就不再是个构造函数,而是个普通方法)

函数重载

 

函数重载: 对类中的一组同名函数, 根据函数实参的参数类型参数个数不同决定调用哪一个对应的函数,这个过程,叫做函数的重载:
 

根据参数类型不同进行重载

people.java:
public class People {
   public  void print (String str) {
     System.out.println("我调用了参数类型为String的方法!");
     System.out.println(str);
   }
   public  void print (int number) {
     System.out.println("我调用了参数类型为int的方法!");
     System.out.println(number);
   }
}

 

Test.java:
public class Test {
   public static void main(String args []) {
     People people1 = new People();
     people1.print("字符串");
   }
}

 

输出:
我调用了参数类型为String的方法!
字符串

 

如果将Test.java中的语句换成:
People people1 = new People();
people1.print(1);

结果

我调用了参数类型为int的方法!
1

 

根据参数个数不同进行重载

People.java:
public class People {
   public  void print (String str) {
     System.out.println("我调用了一个参数的方法!");
   }
   public  void print (String str1, String str2) {
     System.out.println("我调用了两个参数的方法!");
   }
}

 

Test.java:
public class Test {
   public static void main(String args []) {
     People people1 = new People();
     people1.print("参数1", "参数2");
   }
}

 

输出:
我调用了两个参数的方法!

 

如果将Test.java中的语句换成:
public static void main(String args []) {
   People people1 = new People();
   people1.print("参数");
}

 

输出:
我调用了一个参数的方法!

 

 
【注意】函数重载只和参数类型和参数个数有关,和返回值类型无关!! 例如public void XXX()和public String XXX()不构成重载! (这也当然会报错,因为两个函数重复了)同时重载也和参数的命名无关, public void XXX(String str1)和 public void XXX(String str2)是同一个函数,这和函数重载就更没有毛线关系了
 

构造函数重载

 
和函数重载的特性一致,但有一个有趣的一点要注意: 当你没有写入构造函数的时候,系统会默认提供一个无参的构造函数给你, 所以就算没有显式地写type 实例 = new type()也是成立的
 
但是! 当你写了一个有参数的构造函数,但又没有写无参数的构造函数时,type 实例 = new type()就会报错了!(因为默认的无参构造函数已经被你写的有参数的构造函数给取代了嘛~~~~)
 
 

实例变量的默认值,和初始化实例变量

 
如果你声明了一个实例变量,但没有初始化它,那么这个变量会取得一个默认值,默认值依类型决定:
这是每个基本类型对应的默认值
boolean        false
char              '/uoooo'(null)
byte              (byte)0
short             (short)0
int                  0
long               0 (L)
float               0.0 (f)
double           0.0 (d)

 

 
对于引用类型,一律初始化为null
 
例子:
Default.java:
public class Default {
   private  int number;
   private float f;
   private boolean bool;
   private char c;
   private byte b;
   public void printDefaultValues () {
     System.out.println("int的默认值:" + number);
     System.out.println("float的默认值:" + f);
     System.out.println("boolean的默认值:" + bool);
     System.out.println("char的默认值:" + c);
     System.out.println("byte的默认值:" + b);
   }
}

 

 
Test.java:
public class Test {
   public static void main(String args []) {
     Default default1 = new Default();
     default1.printDefaultValues();
   }
}

 

输出
int的默认值:0
float的默认值:0.0
boolean的默认值:false
char的默认值:

 

一般情况下,最好对一个实例变量进行初始化,去覆盖掉默认值
public class Default {
   private  int number = 1;
}

 

访问私有实例变量

私有变量的访问方式我分成两种: 类内访问实例访问
(实际上两者概念上有交叉,但为了方便说明我将两者分开了)
 
类内访问:在定义一个类的时候,在类内部访问私有变量
实例访问: 创建对应类的一个对象,通过对象访问
 

实例访问

创建的对象不能直接访问私有实例变量,但能通过公有的访问器方法访问:
例如:
 
People.java:
public class People {
   private String name;
   public People (String aName) {
     name = aName;
   }
   public String getName () {
     return name;
   }
}

 

在Test.java中,如果我们试图直接通过People的实例对象访问name私有变量:
public class Test {
   public static void main(String args []) {
     People people1 = new People("彭湖湾");
     System.out.println(people1.name);  // 直接通过People的实例对象访问name私有变量
   }
}

 

编译器会友好地提示:The field People.name is not visible,并在运行时候报error,这告诉我们不能不能通过people1.name直接访问私有实例变量name
 
但我们的访问器方法getName是定义为public的呀,所以我们能通过getName方法访问
public class Test {
   public static void main(String args []) {
     People people1 = new People("彭湖湾");
     System.out.println(people1.getName());   
   }
}

 

运行后输出:
彭湖湾

 

私有的变量对于类实例来说本是“不可见”的,但公有的访问器方法却有权让它暴露出来。
 

类内访问

在类定义的代码里,我们可以自由地访问私有实例变量,不过有一点要注意: 私有实例变量的最高访问权限是类,而不仅仅是单个对象(也就是说同一个类定义的不同的对象能够对各自的私有实例变量“互访”)
 
例如,在下我们通过 equalName方法判断People类的两个实例对象的name变量值是否相等
public class People {
   private String name;
   public People (String aName) {
     name = aName;
   }
   public boolean equalName (People other) {
     String otherName = other.name; // 访问另一个对象的私有的name变量
     return name.equals(otherName);
   }
}

 

在Test.java中:
public class Test {
   public static void main(String args []) {
     People people1 = new People("彭湖湾");
     People people2 = new People("XXX");
     People people3 = new People("彭湖湾");
     System.out.println(people1.equalName(people2));
     System.out.println(people1.equalName(people3));
   }
}

 

输出结果:
false   // 说明people1和people2的name值不相等
true    // 说明people1和people3的name值相等

 

在equalName方法中,我们在方法参数中声明了同一个people类的另外一个实例对象other,并通过other.name直接取得它的私有实例变量并在方法中使用。运行是成功的,这意为着私有实例变量并不是为单个对象“所私有”,而是为整个类所“私有”。 这个类下的所有对象,都拥有对同一类下某个对象的私有实例变量的直接的访问权限
 
当然,不同类的对象, 就没有这种直接的访问权限了
 

实例变量和局部变量“交锋”

在方法中, 可以直接通过名称访问实例变量(隐式访问),也可以通过this去显式访问
 
事实上,以下两种方式效果是相同的
public class People {
   private String name;
   public People (String aName) {
     name = aName; // 隐式访问实例变量
   }
}

 

public class People {
   private String name;
   public People (String aName) {
     this.name = aName;   // 显式访问实例变量
   }
}

 

 
当局部变量和实例变量同名的时候,局部变量会覆盖同名的实例变量,让我们看一个例子:
public class People {
   private String name ="实例name变量";
   public People (String name) {
     System.out.println("输出:" + name);  //在构造函数中这样做有些怪异,但为了展示请不要介意
   }
}

 

在People类中,有一个实例变量name, 同时在构造函数中将通过参数的形式引入一个同名的局部变量
name,这个时候,我们通过name访问到的是局部变量name,而不是隐式访问的实例变量name:
 
请看Test.java中的测试:
public class Test {
   public static void main(String args []) {
     People people1 = new People("局部name变量");
   }
}

运行后打印 

输出:局部name变量

 

打印的是“局部name变量”而不是"实例name变量", 这代表, 同名的局部变量覆盖了对应的实例变量
 
嗯嗯,正因如此就会产生一些问题了:我们可能常常希望能够在构造函数中通过参数引入的局部变量的值初始化实例变量,但因为同名覆盖的问题却会带来一些烦恼:
// 无效的写法!
public class People {
   private String name
   public People (String name) {
     name = name; // 两个都取局部变量this,当然无效了
   }
}

 

解决办法有两种:
 
1. 为局部变量取另外一个名称(为了语意的理解可以在同名变量前加上一个字母)
public class People {
   private String name
   public People (String aName) {
     name = aName;
   }
}

 

2. 使用this显式访问实例变量,这样就可以“绕过”局部变量的覆盖
public class People {
   private String name;
   public People (String name) {
     this.name = name;
   }
   public String getName () {
     return this.name;
   }
}

 

小小地总结一下这一小节:
 
1. 在方法中, 可以直接通过名称访问实例变量(隐式访问),也可以通过this去显式访问实例变量
2. 当局部变量和实例变量同名的时候,局部变量会覆盖同名的实例变量
3.  对2中造成的冲突问题,可从两个方向解决:
  3.1 为局部变量取另外一个名称
  3.2  使用this显式访问实例变量
 

静态变量和静态方法

当对一个实例变量加以static修饰符的时候,它就变成了一个静态变量。(“静态”这个词可能并不太能让你推测出它的意义和用法)
例如:
 
public static int  peopleTotal = 0; // 这里设为public只是为了演示

 

静态变量是隶属于类的,而不是隶属于对象,也就是说,静态变量和实例变量是恰好对立的两种变量,前者属于类,后者属于类创建的实例对象。
 
对于实例变量:每创建一个对象,就会创建一份类内所有实例变量的拷贝
对于静态变量: 无论创建多少个对象, 静态变量从始至终都只有一份,为所有对象“共享”
 
示例(访问静态变量):
People.java:
public class People {
   private String name;
   public static int  peopleTotal = 0; // 这里设为public只是为了演示
   public People (String name) {
     this.name = name;
     peopleTotal++; // 每次调用构造函数时候,使得类的peopleTotal静态变量加1
   }
}

Test.java:

public class Test {
   public static void main(String args []) {
         // 创建三个People对象
     People people1 = new People("one");
     People people2 = new People("tow");
     People people3 = new People("three");
     System.out.print(People.peopleTotal); // 输出此时的peopleTotal
   }
}

 

 
结果: 输出3
 
 
我们需要注意两点
第一点,我们最终是通过People.peopleTotal去访问的peopleTotal, 这进一步证明了它是属于类的,而不属于对象
第二点,最后结果输出了3, 这说明:peopleTotal静态变量“从始至终都只有一个”, 连续的三次实例化而调用的构造函数, 使它经历了从0到1,1到2和2到3的过程(反之,如果peopeTotal是实例变量,那么因为每个对象都对这个有个拷贝,则最终输出的应该是1(0+1=1))
 

通过静态方法访问静态变量

如果一个方法仅仅用到静态变量的话,那么这个方法应该作为一个静态方法使用而不是实例方法,也就是说, 它要加上static修饰符,例如:
 
public static int getPeopleTotal

 

让我们对上述的例子稍加改造:
People.java
public class People {
   private String name;
   private static int  peopleTotal = 0; // 和上面的例子不同,这里的静态变量是私有的
   public People (String name) {
     this.name = name;
     peopleTotal++; // 每次调用构造函数时候,使得类的peopleTotal静态变量加1
   }
   public static int getPeopleTotal () {
     return peopleTotal; // 通过静态方法访问私有静态变量
   }
}

 

Test.java:
public class Test {
   public static void main(String args []) {
     People people1 = new People("one");
     People people2 = new People("tow");
     People people3 = new People("three");
     System.out.print(People.getPeopleTotal()); // 输出peopleTotal
   }
}

 

 
结果 输出3
 
静态方法的各种性质和静态变量类似,它也是隶属于类而不是对象
 
上面我们都在强调一点,静态变量, 静态方法隶属于类而不是对象,那么你可能会因此问几个问题:
 
1.对象能够访问静态变量和静态方法吗? (静态变量/方法是否一定要由类调用?)
2.类内定义的实例方法能访问静态变量吗? (类内的静态变量是否一定要由静态方法调用?)
 
下面我将对这两个问题一一解答:

对象能够访问静态变量和静态方法吗?

可以!
实际上,你可以用对象访问静态变量或方法,但你最好不要这样做,因为这容易造成混淆,具体一点说是混淆我们对“静态”的认知,实际上和对象毫无关系的静态变量用对象来调用,会造成我们在理解上的一种矛盾,这降低了程序的可读性。 用类名调用静态方法才是建议的操作
 
// 虽然能达到相同效果但不要这么做!!
Test.java
public class Test {
   public static void main(String args []) {
     People people1 = new People("one");
     People people2 = new People("tow");
       People people3 = new People("three");
     System.out.print(people1.getPeopleTotal()); // 用people1对象调用了静态方法
   }
}

 

 

类内定义的实例方法能访问静态变量吗?

(类内的静态变量是否一定要由静态方法调用?)
可以!
答案当然是可以的,但请注意,如果一个方法仅仅只使用到静态变量(例如我们这个例子),那它应该作为一个静态方法,而不是实例方法,原因和上面相同,这容易混淆我们对于静态变量的认知
 
// 虽然能达到相同效果但不要这么做!!
People.java:
public class People {
   private String name;
   private static int  peopleTotal = 0;
   public People (String name) {
   this.name = name;
   peopleTotal++; // 每次调用构造函数时候,使得类的peopleTotal静态变量加1
   }
   public  int getPeopleTotal () {
   return peopleTotal; // 通过实例方法访问私有静态变量
   }
}

 

Test.java:
public class Test {
   public static void main(String args []) {
     People people1 = new People("one");
     People people2 = new People("tow");
           People people3 = new People("three");
     System.out.print(people1.getPeopleTotal()); // 用people1对象调用了实例方法!!
   }
}

 

【注意】上面说法的前提“一个方法仅仅只使用到静态变量”,如果一个方法不仅仅用到静态变量,情况就不一样了
 

main方法

 
我想每一个写java的筒子们应该都很熟悉的一段代码是public static void main(String args []){ ....}
1.在Java中,main()方法是Java应用程序的入口方法
2. java规范要求必须写成public static void main(String 字符串 []){ ....}的形式
除了字符串数组名称可以任意取,static,void和参数一律不可缺少
 
例如我如果省略static就会导致这一段报错:
 
String args [] 的作用
 
这个字符串数组是用来接收命令行输入参数的,命令行的参数之间用空格隔开
例子:
public class TestMain {
    public static void main(String args[]){
        System.out.println("打印main方法中的输入参数!");
        for(int i=0;i<args.length;i++){
            System.out.println(args[i]);
        }
    }
}

 

假设要执行的这个java文件的路径是D:\Study\basetest\src, 则:
D:\Study\basetest\src>javac TestMain.java
 
D:\Study\basetest\src>java TestMain 1 2 3
打印main方法中的输入参数!
1
2
3
[完]
 
参考资料:
《java核心技术 卷1》—— Cay S. Horstmann, Gary Cornell
《Java中的main()方法详解》 —— 熔岩   http://lavasoft.blog.51cto.com/62575/53263
 

 

其实啊,我只是把你们喝咖啡的时间,都用来喝啤酒而已
目录
相关文章
|
14天前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
44 0
|
2天前
|
存储 Java
java的对象详解
在Java中,对象是根据类模板实例化的内存实体,具有唯一标识符、属性及行为。通过`new`关键字实例化对象并用构造方法初始化。变量存储的是对象引用而非对象本身,属性描述对象状态,方法定义其行为。Java利用垃圾回收机制自动处理不再使用的对象内存回收,极大地简化了对象生命周期管理,同时对象具备封装、继承和多态性,促进了代码的重用与模块化设计。这使得Java程序更易于理解、维护和扩展。
|
2天前
|
Java
java的类详解
在 Java 中,类是面向对象编程的核心概念,用于定义具有相似特性和行为的对象模板。以下是类的关键特性:唯一且遵循命名规则的类名;描述对象状态的私有属性;描述对象行为的方法,包括实例方法和静态方法;用于初始化对象的构造方法;通过封装保护内部属性;通过继承扩展其他类的功能;以及通过多态增强代码灵活性。下面是一个简单的 `Person` 类示例,展示了属性、构造方法、getter 和 setter 方法及行为方法的使用。
|
6天前
|
Java API 开发者
【Java字节码操控新篇章】JDK 22类文件API预览:解锁Java底层的无限可能!
【9月更文挑战第6天】JDK 22的类文件API为Java开发者们打开了一扇通往Java底层世界的大门。通过这个API,我们可以更加深入地理解Java程序的工作原理,实现更加灵活和强大的功能。虽然目前它还处于预览版阶段,但我们已经可以预见其在未来Java开发中的重要地位。让我们共同期待Java字节码操控新篇章的到来!
|
4天前
|
Java
Java 对象和类
在Java中,**类**(Class)和**对象**(Object)是面向对象编程的基础。类是创建对象的模板,定义了属性和方法;对象是类的实例,通过`new`关键字创建,具有类定义的属性和行为。例如,`Animal`类定义了`name`和`age`属性及`eat()`、`sleep()`方法;通过`new Animal()`创建的`myAnimal`对象即可调用这些方法。面向对象编程通过类和对象模拟现实世界的实体及其关系,实现问题的结构化解决。
|
8天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
4天前
|
Java API 开发者
【Java字节码的掌控者】JDK 22类文件API:解锁Java深层次的奥秘,赋能开发者无限可能!
【9月更文挑战第8天】JDK 22类文件API的引入,为Java开发者们打开了一扇通往Java字节码操控新世界的大门。通过这个API,我们可以更加深入地理解Java程序的底层行为,实现更加高效、可靠和创新的Java应用。虽然目前它还处于预览版阶段,但我们已经可以预见其在未来Java开发中的重要地位。让我们共同期待Java字节码操控新篇章的到来,并积极探索类文件API带来的无限可能!
|
15天前
|
存储 Java
Java编程中的对象序列化与反序列化
【8月更文挑战第28天】在Java世界中,对象序列化与反序列化是数据持久化和网络传输的关键技术。本文将深入浅出地探讨这一过程,带你领略其背后的原理及应用,让你的程序在数据的海洋中自由航行。
|
16天前
|
机器学习/深度学习 人工智能 算法
探索人工智能在医疗诊断中的应用与挑战Java编程中的对象和类:基础与实践
【8月更文挑战第27天】随着人工智能(AI)技术的飞速发展,其在医疗领域的应用日益广泛。本文深入探讨了AI技术在医疗诊断中的具体应用案例,包括图像识别、疾病预测和药物研发等方面,并分析了当前面临的主要挑战,如数据隐私、算法偏见和法规限制等。文章旨在为读者提供一个全面的视角,理解AI在改善医疗服务质量方面的潜力及其局限性。
|
16天前
|
Java Spring 容器
Java获取接口的所有实现类方法
这篇文章介绍了在Java中获取接口所有实现类的方法,包括使用JDK的ServiceLoader(SPI机制)和Spring Boot中的@Autowired自动注入及ApplicationContextAware接口两种方式。
37 1