一、Java 对象和类
- 面向对象语言三大特性:封装、继承、多态;
- 对象:描述客观事物的一个实体;
- 类:类是封装对象的属性和方法的载体,反过来说具有相同属性和行为的一类实体被称为类;类行为:方法;属性:成员变量
- 定义类:
[访问修饰符] class 类名{ //class是声明类的关键字,类名首字母大写
//代码
} - java中权限修饰符
访问位置 private 默认 protected public 同一个类 √ √ √ √ 同包或其子类 × √ √ √ 其他包的类或子类 × × √ √ 其他包的非子类 × × × √ - 定义属性:
[访问修饰符] 数据类型 属性名; - 定义成员方法:
[权限修饰符] 返回值类型 方法名(参数类型 参数1名,....){
//方法体
return 返回值; //若无返回值,此句可以不写(但仍可以用return ;退出该方法),并用void关键字声明返回值类型
}
注:访问修饰符可选;
参数列表可选;
二、创建和使用对象
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字new来创建一个对象。
- 初始化:使用new创建对象时,会调用构造方法初始化对象。
- 类名 对象名 = new 类名();
new是关键字 类名()为对象的构造方法
public class Puppy{ int puppyAge; //成员变量 public Puppy(String name){ // 这个构造器仅有一个参数:name System.out.println("小狗的名字是 : " + name ); } public void setAge( int age ){ puppyAge = age; } public int getAge( ){ System.out.println("小狗的年龄为 : " + puppyAge ); return puppyAge; } public static void main(String []args){ //程序执行的入口 /* 创建对象 */ Puppy myPuppy = new Puppy( "tommy" ); /* 通过方法来设定age */ myPuppy.setAge( 2 ); /* 调用另一个方法获取age */ myPuppy.getAge( ); /*你也可以像下面这样访问成员变量 */ System.out.println("变量值 : " + myPuppy.puppyAge ); } }
结果:小狗的名字是 : tommy 小狗的年龄为 : 2 变量值 : 2
- 使用对象:对象.属性 对象.方法名
- 对象数组:对象数组的数据类型就是具体的类名,对象数组存储的就是这个类的对象,每个元素就是一个对象。
-
源文件声明规则:
- 一个源文件中只能有一个public类
- 一个源文件可以有多个非public类
- 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
- 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
- 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
- import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。Java包
三、方法的重载(不同于重写即覆盖,后面会说到)
方法重载即在同一个类中允许同时存在一个或多个同名方法,构成重载的条件:1.参数类型不同;2.参数顺序不同;3.参数个数不同;
注意:方法的返回值类型不能作为判断是否重载的依据;
可以定义不定长参数方法:返回值 方法名(数据类型 ... 参数名称) 例如:void main(int[ ] a){....}
package cn.galc.test; public class TestOverLoad { void max(int a, int b) { System.out.println(a > b ? a : b); } /*int max(int a, int b) { //不构成重载 return a > b ? a : b; }*/ void max(float a, float b) { System.out.println(a > b ? a : b); } }
四、this关键字
根据面向对象的基本语法,每当调用变量或者函数的时候,都要按照类名.变量(函数)的格式来调用,意即每个变量或函数都必须属于某一个实际的对象而不是一个类(static的除外).
1.Java中规定使用this关键字来表示“本类对象的引用”,this关键字被隐式地用于引用对象的成员变量和方法。
private void setName(String name){ this.name = name; 成员变量name _| |_ 形参name }
2.this引用的就是本类的一个对象,在局部变量或方法覆盖了成员变量时,就需要添加一个this关键字明确引用的是成员变量还是局部变量或方法。
3.this还可以作为方法的返回值:
public Book getBook(){ return this; //返回Book类引用 }
4. this在不会产生混淆的前提下是可以省略的,但一般都会加上:
package con.ytb.test; public class Pepole{ String name; //成员变量 void say(String name){ System.out.println("我的名字是:"+this.name); //我的名字是:李明 System.out.println("我的名字是:"+name); //我的名字是:李四 }
public static void main(String[] args){
Pepole p = new Pepole(); p.name = "李明"; p.say("李四"); }
}
五、构造方法
是一个与类同名的方法,对象的创建就是通过构造方法完成的。
- 构造方法无返回值(不用void修饰)
- 默认构造犯法没有参数,因此参数列表可选
- 构造方法名和类名相同
- 没实例化一个对象时,类都会自动调用构造方法
1.只能在类中没有定义任何构造方法时,编译器会自动创建一个不带参数的构造方法,但不执行任何代码;如果类中定义的构造方法都不是无参的构造方法(可以理解为无参的构造函数被覆盖),不会自动设置默认无参构造方法
2.构造方法可以重载,同一个类中可以有多个重载的构造方法,以参数的个数,类型,顺序
3.使用this调用重载的构造方法,只能在构造方法中使用,且必须是构造方法的第一条语句
- 构造方法的作用
- 构造函数用来生成并初始化对象
- 构造函数可以通过函数的重写给对象赋初始值,简化代码
package com.ytb; public class Pepole { String name; //成员变量 int age; String address; Pepole(){ //无参构造方法,可以省略不写 System.out.println("这是无参构造方法"); } Pepole(String name,int age){ //构造方法重载,有参构造方法 this.name = name; this.age = age; System.out.println("这是有参构造方法"); } Pepole(String name,int age,String addrss){ //构造方法重载,有参构造方法 //this.name = name; //this.age = age; this(name,age); //使用this调用其它构造方法,简化代码 this.address = addrss; System.out.println("这是有参构造方法"); } void say(){ //成员方法 System.out.println("我的名字是:"+this.name+" "+"年龄是:"+this.age+" "+"地址是:"+this.address); } public static void main (String[] args){ Pepole p = new Pepole(); //创建对象会调用默认构造方法 p.name = "李明"; p.age = 20; p.address = "北京"; p.say(); Pepole pp = new Pepole("李四",50); //此处不会调用无参构造方法,会调用Pepole(String name,int age) pp.address = "西安"; pp.say(); Pepole ppp = new Pepole("唐三",18,"斗罗大陆"); ppp.say(); } } 输出结果: 这是无参构造方法 我的名字是:李明 年龄是:20 地址是:北京 这是有参构造方法 我的名字是:李四 年龄是:50 地址是:西安 这是有参构造方法 这是有参构造方法 我的名字是:唐三 年龄是:18 地址是:斗罗大陆
在后续类的继承中还会说到构造方法,未完待续。。。
六、静态常量、变量和方法
由static修饰的变量、常量和方法,均属于静态成员,static成员前可以有访问权限限定修饰(private、public、protectd)
- 静态成员变量属于类所有,区别于个别对象,也就是说,它不依赖类特定的实例,被类的所有实例共享。可以在本类或其他类中使用"类名.静态类成员"调用
- 静态变量和静态方法的作用: 方便在没有创建对象的情况下来进行调用(方法/变量);为了提供共享数据或方法,比对象优先加载
注意:1.静态方法中不可以使用this关键字,也不能使用super,因为实例成员与特定的对象关联;
2.要在static方法中调用非静态的变量或者方法,可以先实现你所想要调用的非静态变量或方法所在的类的对象,然后通过个这对象的引用就可以访问非静态的方法和成员;
2.在静态方法中不能直接调用非静态方法,不能直接访问所属类的实例变量和方法;
3.java中规定不能将方法体中的局部变量声明为static;
4.如果在执行类时,希望先执行类的初始化操作,可用static定义一个静态代码块,当java虚拟机(JVM)加载类时,就会执行该代码块;
package com.ytb; public class StaticObject { private String str1 = "object"; private static String str2 = "static";
static{ //静态代码块,只会在类加载的时候执行一次
System.out.println("执行静态代码块");
} StaticObject(){ //构造方法 } public void out(){ //普通方法 System.out.println(str1); System.out.println(str2); //str2是静态成员变量 print(); //非静态成员方法中是可以访问静态成员方法/变量的 } public static void print(){ //静态方法 //System.out.println(str1); //str1是非静态成员变量,无法访问 System.out.println(str2); //out(); //静态方法中不能访问非静态成员方法和非静态成员变量 } public static void main(String[] args){ //main()方法是static方法 StaticObject s = new StaticObject(); s.out(); //通过实例调用非静态方法 //s.print(); //不能调用 StaticObject.print(); //通过类名.方法名调用 } } 输出结果:
执行静态代码块 object static static static
- static修饰的静态变量 和 没有被static修饰的实例变量
1.对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(不推荐)
2.对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内在中有多个拷贝,互不影响(灵活)
3.一般在需要实现以下两个功能时使用静态变量: 在对象之间共享值时;方便访问变量时
七、final变量、final方法、final类
- final变量(常使用大写字母表示)
1)final关键字用于声明变量,一旦设定,就不可以再改变变量的值;
2)final变量必须在声明时对其进行赋值操作
3)一旦一个对象引用被修饰为final后,它恒定指向一个对象,无法改变让其指向另一个对象,但是它指向的对象的内容是可变的
4)一个既是final又是static的字段只占据一段不能被改变的存储空间,对于变量,表示一旦给值就不可修改,并且通过类名可以访问;对于方法,表示不可覆盖,并且可以通过类名直接访问
5) 若方法的某个参数被final修饰了,则代表了该参数是不可改变的
package com.ytb; import java.util.Random; public class FinalDta { static Random random = new Random(); private final int VALUE_1 = 9; //声明一个final常量 private final int VALUE_2 = 10; private final Pepole pe = new Pepole(); //声明一个final的引用 private Pepole pee = new Pepole(); private final int[] a = {1,2,3}; private int BLANK_VALUE; //声明时没有赋值称为空白final变量 public FinalDta(){ BLANK_VALUE = 14; //构造方法赋值 } int doIt(final int x){ //设置final参数,不可改变x的值 //x = x+1; //i报错,x值不能改变 return x; } void doSomething(){ final int i = 7; //局部变量声明为final,不可以改变i的值 //System.out.println("i的值:"+i++); //i++报错,i值不能改变 } public static void main(String[] args){ FinalDta fin = new FinalDta(); //fin.pe = new Pepole(); //不能指向其他引用 //fin.VALUE_1 = 100; //不能改变其值 } }
2. final 方法
- final方法不能被重写
public class B extends A { public static void main(String[] args) { } public void getName() { } } class A { /** * 因为private修饰,子类中不能继承到此方法,因此,子类中的getName方法是重新定义的、属于子类本身的方法,编译正常 */ private final void getName() { } /* 因为pblic修饰,子类可以继承到此方法,导致重写了父类的final方法,编译出错 public final void getName() { }*/ }
/****************在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化***********************/ public class Test { public static void main(String[] args) { String a = "hello2"; final String b = "hello"; String d = "hello"; String c = b + 2; String e = d + 2; System.out.println((a == c)); //true final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,在使用到b的地方会直接将变量b替换为它的值 System.out.println((a == e)); //false 变量d的访问需要在运行时通过存储地址来进行 } } /****************************************************************/ public class Test { public static void main(String[] args) { String a = "hello2"; final String b = getHello(); //变量b在这里是使用getHello()方法对其进行初始化,它要在运行期才能知道其值 String c = b + 2; System.out.println((a == c)); //false } public static String getHello() { return "hello"; } }
- private 方法,子类无法访问,不能被覆盖(方法重写);类的private方法会隐式地被指定为final方法。
- private final 方法:可以被子类覆盖条件: 一个对象向上转型为它的基本类型并调用相同方法
package com.ytb; public class Test { public final double i = Math.random(); public static double j = Math.random(); public static void main(String[] args) { Test myClass1 = new Test(); Test myClass2 = new Test(); //myClass1.i = 10; 报错,不能改变i的值 System.out.println(myClass1.i); System.out.println(myClass1.j); System.out.println(myClass2.i); //myClass2.j = 14; j的值可以改变 System.out.println(myClass2.j); } }
- final类:定义为final的类不能被继承,不允许其他人对这个类进行任何改动:final class 类名{ }