java做为一门面向对象的语言, 类和对象是最重要的概念之一,下面,就让咱们来看看java中类的基本结构是怎样的:java
一个简单的java类主要可由如下几个部分(要素)组成:数组
1.实例变量函数
2.构造函数 测试
3.更改器方法this
4.访问器方法spa
例如:命令行
class Myclass { field1... // 声明实例变量(实例域) field2... // 声明实例变量(实例域) constructor.. // 构造函数 getMethod1.. // 访问器方法1 getMethod2.. // 访问器方法2 setMethod1... // 更改器方法1 setMethod2... // 更改器方法2 }
也许你对java类的运用早已了熟于心了,但对结构的细化和分析有助于你进一步的了解对象
让咱们看一下下面这个实例three
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对象调用了实例方法!! } }
【注意】上面说法的前提“一个方法仅仅只使用到静态变量”,若是一个方法不只仅用到静态变量,状况就不同了
我想每个写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
[完]