java对象部分
1—类的理解
-类是一个构造对象模板,类的主要成员有三个—属性(域),构造器,方法。
1.1属性,构造器和方法
- 类的属性是指定义在类中的变量和常量,也成为类的域(field),在声明属性时常把属性定义为private的,这是类封装性的体现,私有化域,提供公有的get,set方法来设置和返回域。
e.g
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 构造器:类的构造器格式要求只能是访问修饰符加构造器名称(参数列表){}。类默认会提供一个空参的构造器,如果重写了构造器,那么就只能调用重写的构造器了。对于构造器来说不能写返回值类型。
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
super();
}
}
- 方法:声明方法时必须要写返回值类型,没有可写为void。有返回值类型的方法需要在方法体中提供对应类型的return语句,否则报错。如果定义一批类型相同但是个数不确定的参数列表可以用…来表示e.g public ArrayList setName(String… names)
e.g有返回值的方法
public String getName(){
return this.name;
}
无返回值的方法
public void setName(String name){
this.name=name;
}
1.2方法的参数
- 声明类的方法时可以定义形参,形参就是调用此方法时需要向方法中传递的参数模板(实际上传入的参数是实参,在操作中调用方法时传入的变量不需要写参数类型(一般都会提前定义好,调用方法时只传入变量名)。但是形参定义时需要写明参数的数据类型。
- e.g 下面程序中定义add方法时括号中的内容int x,int y就是定义了两个int类型的形参,调用方法时使用的i,b就是两个实参。
public class Person{
public static void main(String[] args){
int i=1;
int b=2;
int c=add(i,b);
System.out.println("c="+c);
}
public static int add(int x,int y){
return x+y;
}
}
1.3参数的传递机制和理解
- 关于java的参数传递机制是值传递机制,对于基本数据类型的实参来说传递给方法的其实是一个实参的拷贝,然后经过方法之后如果不写返回值,那么对于实参的值是没有影响的,(仅会在方法运行时影响方法中的参数的值即实参的拷贝值)。
- e.g 验证值传递机制,下方代码是上一个代码的小改动,通过下方代码可以看出方法内x的值更改了,但是调用方法后i的值并没有发生变化
public class Person{
public static void main(String[] args){
int i=1;
int b=2;
add(i,b);
System.out.println("i="+i);
}
public static void add(int x,int y){
x= x+y;
System.out.println("x="+x);
}
}
程序输出
x=3
i=1
- 对于值传递机制本人认为从内存开辟角度来看比较容易理解,对于一个java类的实例,java虚拟机会提供一个堆空间来存储,实例中的定义的变量和方法却是放到栈空间存储,而方法中的数据则是运行时由虚拟机分配的栈空间来存储的,这个栈空间和实例中存储变量和方法的栈空间不同,所以当运行方法时,操作的数值只是在新分配的栈空间中有效果,如果在方法结束之前不返回结果,那么对于原来栈空间的变量就不会产生影响。
- 但是当传入的实参是对象的属性的引用时就会有所不同,这种转递方式习惯上叫引用传递
这种情况下即使调用的方法不返回结果,也会对传入的实参的属性会有影响。让我们还是从内存的角度来看这个问题,在堆中的对象会指向栈空间中的属性,当把这个引用作为实参传递给方法时,方法得到的值拷贝其实是地址的引用的拷贝,这时方法对这个引用进行修改操作后,原有的引用也会发生相应的变化。
1.4类常见的关系
- 常见类的关系有依赖,继承。继承和多态性有关。依赖则是一个类中的属性可以定义为另一个类或者是这个类的方法需要访问另外一个类。
2—对象
2.1实例
对象是某个类的实体(也叫实例),在java的虚拟机中是存储在堆空间的,声明对象并初始化时是把这个堆内存地址的引用赋给了对象变量。
e.g 下方代码声明了名为person的Person类的对象。
Person person;
2.2类的实例化
通过new来条用类中定义的构造器完成的。这一操作会开辟储存对象的堆空间,开辟存储变量和方法栈空间,还有存储静态成员和常量的方法区。
e.g 声明对象+实例化,调用Person类空参的构造器来实例化。
Person person=new Person();
2.3java面向对象的三大特性
-1.封装
-2.继承
-3.多态
- 封装性体现在定义类的属性时的私有化操作,即把类的访问修饰符写成private,只在本类可见,之后提供Public的方法来设置和获取属性。当其他类想要调用属性时只能通过调用方法来得到,保证安全性。
- 类的继承就是指子类可以继承父类(也可以说成父类可以拓展子类),子类可以通过继承关系来获得父类的属性和方法,当然如果是private的属性和方法也可以获得。对于protected和public的属性和方法,子类可以直接使用,但是对于缺省和private的属性,需要子类通过super.field或者super.method();来使用。使用继承是要注意继承对子类而言是单继承的(一个子类只能继承一个父类,但是一个父类可以被多个子类来继承)。
e.g类的继承
public class Student extends Person{//继承了1.1中的Person类,Student类是子类。
private int studentID=123456;
}
- 再者就是多态-在解释多态性之前,需要说明方法的重载和重写,方法的重载是方法的形参列表不同,可能方法体有所不同,但是方法名和返回值类型还有访问修饰符都必须相同,它可以实现一个方法可以通过传入不同类型的参数或者不同个数的参数来获得不同的结果。
e.g 下面这些代码是一个重载的例子,第一个speak方法在调用时会输出一串字符串,但是第二个speak方法在调用时能打印传入int类型参数的值。
class Animal {
private int name;
public void speak() {
System.out.println("Animal speak");
}
public void speak(int i) {
System.out.println(i);
}
}
- 方法的重写则是子类继承父类之后对父类中原有的方法体内容进行改写,但是方法的形参列表是不能改变的(与重载不同)。使用重写则可以实现传入相同的参数获得与父类不同的结果。
e.g 以下代码重写了父类Animal中的speak空参的方法,在使用Cat类的实例调用speak方法时则会输出重写之后的内容。
class Cat extends Animal{
@Override
public void speak() {
System.out.println("miaomiaojiao");
}
}
- 当声明对象变量时可以使用父类的对象类型来声明,初始化用子类的构造器。即把子类对象赋给父类,这就是多态的一种表现形式,通过在子类中重载和重写方法,可以让这个父类对象完成多样化的操作。
e.g如果在一个main方法或者测试方法中写入以下代码并导入Cat和Animal类,就可以测试多态一种形式
Animal cat=new Cat();
cat.speak();
- 子类对象赋给父类得到的父类对象变量是可以强转为子类对象变量的。
2.4抽象类
- 抽象类其实就是在声明类时添加了abstract修饰符,表示这个类中的部分方法没有实现,需要继承它的可以实例化的子类来实现(只需要在定义子类方法时对父类未实现的方法进行重写就可以),抽象类是不能实例化的 ,但是实现了所有抽象方法的子类可以实例化。
e.g简单的抽象类,add方法时抽象方法
public abstract class TestAbstractClass {
private int num;
public abstract int add(int a,int b);
}
以下是一个实现类
class InstanceClass extends TestAbstractClass{
@Override
public int add(int i,int j) {
return i+j;
}
}
- 只要有抽象方法的类一定是抽象类,可实例化的类一定没有抽象方法。
2.5类的静态成员
- 使用static修饰的变量时静态变量。静态变量和普通变量的区别在于,静态变量直属于类,不属于对象,这就意味着一个类无论创建多少个对象只会有一个静态变量,但是普通变量的个数会随着对象的增加而增加。静态变量是在方法区中储存的,其实方法区也是一个堆空间。调用静态变量时直接用类名.变量名就可以。例如Math.PI。
- static修饰的方法时静态方法,静态方法和静态变量都是直属于类,在静态方法中只能使用类的静态变量,因为静态成员会随着类的加载而加载,但是普通成员则是需要等待对象的创建。
- 对于类的初始化和加载时机有以下几种情况:1.构造类的实例 2.访问类的static方法和变量 3.反射访问类时 4.初始化子类时,如果父类未初始化,则先初始化父类。需要注意,访问类的常量时不会触发类的初始化,即使常量有static修饰也不会初始化。
2.6对象包装器
- java的基本数据类型都有对应的类,可以通过类来包装基本数据类型来实现一些只有类才能实现的操作。
基本数据类型 | 对应的类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
2.7内部类
- 内部类可分为4中类型,成员内部类,静态内部类,方法内部类,匿名内部类。内部类就是定义在一个类中的类,可以定义在域中或者方法中。内部类可以调用外部类的变量和方法,但是外部类想调用内部类的变量和方法时需要通过内部类的实例来调用。
- i 成员内部类,和定义变量一样的声明方式
public class TsetInnerClass {
private String name;
private class InnerClass{//定义一个成员内部类
private int id;
public InnerClass() {}
public void setId(int id) {
this.id=id;
}
}
public static void main(String[] args) {
InnerClass inner=new TsetInnerClass().new InnerClass();//成员内部类的调用
}
}
- ii 静态内部类,使用static修饰的成员内部类就是静态内部类
e.g注意和成员内部类的区别
public class TsetInnerClass {
private String name;
private static class InnerClass{//静态内部类,注意不能使用外部类中非静态的属性和方法
private static int id;
public InnerClass() {}
public static void setId(int id) {
InnerClass.id=id;
}
}
public static void main(String[] args) {
InnerClass inner=new TsetInnerClass.InnerClass();//初始化静态内部类
}
}
- iii方法内部类是定义在类中的方法中的类,这种类只对包含类定义的方法可见。
- e.g.
public class TsetInnerClass {
private int num;
public int add(int i,int j) {
class Info{//定义了一个方法内部类
public void info() {
System.out.println("传入的参数是i="+i+",j="+j);
}
}
Info in=new Info();//在外部类的方法内初始化方法内部类
in.info();//调用内部类方法
return i+j;
}
public static void main(String[] args) {
TsetInnerClass ad=new TsetInnerClass();
int i=ad.add(1,2);
System.out.println("计算结果是:"+i);
}
}
- iv 匿名内部类:定义在类中但是不指定名字,这种内部类只能被调用一次。
e.g.
public class TestInnerClass2 {
public static void main(String[] args) {
System.out.println("地址是:"+new Address("中国","河北","石家庄"));//使用匿名内部类对象来传入参数
}
}
class Address{//定义一个地址类
private String country;
private String city;
private String town;
public Address(String country, String city, String town) {
super();
this.country = country;
this.city = city;
this.town = town;
}
@Override
public String toString() {
return "Address [country=" + country + ", city=" + city + ", town=" + town + "]";
}
}
2.8this和super
- this表示的对象是调用当前方法或者变量的对象,对于static声明的成员或者方法,则不能用this,因为static声明的方法和变量属于类而不是对象
- super用于调用父类成员。e.g
super.constructor()
。