Java SE笔记(6)

Java SE笔记

六、类和对象

1.编程语言的发展历程

  • 机器语言-直接由计算机的指令组成,指令、数据、地址都以“0”和“1”的符合串组成;可以被计算机直接执行。
  • 汇编语言-用容易理解和记忆的符合表示指令、数据以及寄存器等,抽象层次很低,程序员需要考虑大量的机器细节。
  • 高级语言-屏蔽了机器细节,提高了语言的抽象层次接近于人的自然语言,60年代出现的结构化编程语言提出了结构化数据和语句,数据和过程抽象等概念。
  • 面向对象的语言-与已往的各种语言的根本不同是,它的设计出发点就是为了更能直接的描述问题域中客观存在的事物。

2.面向对象概念

  • 面向过程编程
    传统的C语言属于面向过程编程。面向过程解决问题的思路:通常是分析出解决问题所需要的步骤,然后用方法把这些步骤一步一步实现,最后一个一个依次调用方法来解决。

  • 面向对象编程
    这些对象没有先后顺序,共同作用才构成了整个系统。我们只要用代码设计出这几个类型的对象,然后让他们互相通信、传递消息就可以完成系统功能。

  • 面向对象基本概念

  • 抽象(abstract) :

    • 从事物中舍弃个别的非本质特征,抽取共同的本质特征
    • 只考虑与问题域相关的信息,而忽略与问题域不相关的部分
  • 对象(object):

    • 可以是有形的,也可以是无形的(如一个客户,一张银行卡,窗体中 的一个按钮等等)
    • 对象构成世界的一个独立单位
    • 具有自己的静态结构(属性)和动态行为(方法)
    • 每个对象有自己的唯一标识
  • 类:

    • 类是一组具有相同属性和行为的对象的抽象,类的作用是用来创建对象,对象是类的一个实例
  • 类和对象的关系:

    • 抽象和具体的关系
    • 每一个类在某一时刻都有零个或更多的实例,类是生成对象的模板
    • 一个类定义了使用哪些数据来描述属性,每一个对象都有相应的属性值数据,一个类通过一系列方法来定义行为,这些方法能在每个对象中被激活
  • 面向对象主要特征

  • 封装(encapsulation):

    • 所谓封装是把对象的属性和行为结合在一个独立的系统单位内部
    • 尽可能隐蔽对象的内部细节,只向外提供接口
    • 降低对象间的耦合度
    • 封装的重要意义:
      • 使对象能够集中而完整地描述并对应一个具体事物
      • 体现了事物的相对独立性,使对象外部不能随意存取对象的内部数据
  • 继承(inheritance):

    • 也成泛化,继承性是子类自动共享父类属性和方法的机制,在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入自己若干新的内容
    • 继承简化了人们对事物的认识和描述,有益于软件复用,是00技术提高软件开发效率的重要原因之一
    • 是类之间的一种关系,一般类与特殊类之间的关系
    • 继承关系的语句:“is a kind of”
  • 多态(polymorphism):

    • 指同一种命名可具有不同的语义
    • 00方法中,常指在一般类中定义的属性或方法被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为,对于子类,可用不同的方法替代实现父类的服务方法

3.类的定义

什么是类

  • 把相似的对象划归成一个类
  • 在软件设计中,类,就是一个模板,它定义了通用与一个特定种类的所有对象的属性(变量)和行为(方法)。

什么是对象

  • 类(class) - 是对某一事物的描述

  • 对象(object) - 是实际存在的某类事物的个体,也称为实例(instance)

  • 类是创建对象的模板,对象是类的实例。
    在这里插入图片描述

  • 类的格式

[类修饰符] class 类名
{
	类的成员
	...
}
  • 修饰符一般为public
  • 注意类名的命名规范。类名一般大写
  • 类的成员:
    • 成员变量(属性)
    • 成员方法(方法)
    • 嵌套类
  • 通过“.”调用属性和方法
class Employee{
	String name;
	int age;
	double salary;
	public String showName(){
		System.out.println(name);
		return name;
	}
	public int showAge(){
		System.out.println(age);
		return age;
	}
	public void updateName(String name2){
		name = name2;
	}
	public void getSalary(){
		System.out.println("The salary of this month is 2000");
	}
}

上述代码String name;int age;double salary;为属性,showName(),showAge(),updateName(String name2),getSalary()为方法

  • 类的成员
    • 成员变量:[修饰符] 类型 属性名 = [默认值]

    • 其中修饰符有:public、private、protected,也可以省略不写。

    • 方法:[修饰符] 返回值类型 方法名(形参列表){ 语句 }

数组是类类型

  • 第一种方式:
		Person[] persons = new Person[3];
		persons[0]=new Person();
		persons[1]=new Person();
		persons[2]=new Person();
		System.out.println(persons[0].getAge());
  • 第二种方式:
Person p1 = new Person();
		p1.setName("张三");
		p1.setAge(25);
		Person p2 = new Person();
		p2.setName("李四");
		Person p3 = new Person();
		p3.setName("王五");
		Person[] persons = new Person[3];
		persons[0]=p1;
		persons[1]=p2;
		persons[2]=p3;
		System.out.println(persons[0].getAge());
		System.out.println(persons[1].getName());
  • 第三种方式:
Person[] persons = {p1,p2,p3,new Person()};
		System.out.println(persons[0].getAge());
		System.out.println(persons[3].getAge());

foreach 增强for循环
从Java5之后,Java提供了一个种简单的循环;foreach循环,这种循环遍历数组和集合更加简洁。使用foreach循环遍历数组和集合元素时,无须获得数组和集合长度,无须根据索引来访问数组元素和集合元素,foreach循环自动遍历数组和集合的每个元素。

  • foreach循环的语法格式:
    for(type variableName: array | collection){
    //自动迭代访问每个元素
    }
String[] str= new String[]{"hello","world","aaa","bbbb"};
	for(String s:str){
		System.out.println(s);
	}
  • 用foreach给数组赋值
public static void main(String[] args) {
		String[] str= new String[]{"hello","world","aaa","bbbb"};
		for(String s:str){
			s="aaa";
			System.out.println(s);
		}	
		System.out.println(Arrays.toString(str));
	}

注意:使用foreach循环迭代数组元素时,并不能改变数组元素的值,因此不要对foreach的循环变量进行赋值

  • 用foreach遍历类类型的对象
Person p1 = new Person();
		p1.setName("张三");
		p1.setAge(25);
		Person p2 = new Person();
		p2.setName("李四");
		Person p3 = new Person();
		p3.setName("王五");
		Person[] persons = {p1,p2,p3,new Person()};
		for(Person p:persons){
			System.out.print(p.getName());
			System.out.println(p.getAge());
		}

总结:java当中有两种类型:基本数据类型(8种)、引用数据类型(数组、类、接口)

4.封装

  • 信息隐藏,隐藏对象的实现细节,不让用户看到
  • 将东西包装在一起,然后以新的完整形式呈现出来
    • 例如,两种或多种化学药品组成一个胶囊
    • 讲方法和属性一起包装到一个单元中,单元以类的形式实现
  • “隐藏属性、方法或实现细节的过程称为封装”

封装的概念

  • 封装简单来说就是信息隐藏,指的是用来限制对象中内容访问的一种机制;
  • 封装可以被描述为一个保护,用来阻止外部访问内部的代码和数据;
  • 使用封装我们可以实现代码可维护性,代码的灵活性和可扩展性。

Java中的封装

  • 类就是一个封装体,封装是属性和方法;
  • 方法也是一个封装体,将业务代码封装到方法中,外部只能使用方法,而对方法中执行的代码毫无所知,即简化了外部的使用,又提高了安全性;
  • 通过访问修饰符可以限制类中属性和方法的访问级别

5.访问说明符

  • 信息隐藏是OOP最重要的功能之一,也是使用访问说明符的原因
  • 信息隐藏的原因包括:
    • 对任何实现细节所作的更改不会影响使用该类的代码
    • 防止用户意外删除数据
    • 此类易于使用

在这里插入图片描述
访问权限修饰符

  • 用来控制类的成员和类的使用范围
  • 类成员的访问权限修饰符:private、default、protected、public
  • 类的访问权限修饰符:public、default
privatedefaultprotectedpublic
同一类
同一包中的类
不同包中的子类
其他包中的类

访问控制的限制程度从高到低如下图所示。注意,Default不是一个修饰符,它只是用来表示一种不加任何修饰符时的状态。
在这里插入图片描述
6.方法

  • 方法的定义:方法是完成某个功能的一组语句,通常将常用的功能写成一个方法
  • 方法的格式
[访问控制符] [修饰符] 返回值类型 方法名(参数类型 形式参数, 参数类型 形式参数, ...)
{
	方法体
}
  • 修饰符:public、static被称为修饰符;
  • 返回值类型:用来说明该方法运算结果的类型。如果返回其他类型,编译就可能出错;
  • 方法名:它作为调用时引用方法的标识;
  • 参数列表:方法的参数个数可以是0到多个,每个参数前面要声明参数的数据类型;每个参数要用逗号分开。也可以一个参数都没有。
  • 方法体:它是一个语句块,执行特定的功能操作。对于返回值类型的方法,方法体当中最后一个语句是return关键字,它的作用是把方法的执行(运算)结果返回到方法外部。
  • return 表达式:这里,进一步分析,return后面的表达式就是方法的返回值。需要注意表达式的类型,必须与方法头中声明的“返回类型”相匹配。
  • 方法的执行过程:
    • main开始执行 – 在main方法中调用我们自己写的方法
    • 方法在调用的时候,会在栈中开辟一块区域叫栈帧,栈帧中存放该方法中的形式参数和局部变量,当该方法调用结束时,栈帧消失。
      方法的分类
  • 根据参数个数:
    • 无参方法
    • 有参方法
  • 根据返回值类型
    • 有返回值的方法:
      • 基本数据类型
      • 引用数据类型
    • 无返回值的方法
      • void
  • 使用方法时的注意问题
    • 形参必须注明数据类型
    • 实参直接写,不需要类型声明
    • return只能返回一次
    • 遇到return语句,方法结束执行,后续语句不执行
    • 方法的返回值,必须与方法声明中的返回值类型匹配
    • 方法定义,不能写在main()中
    • 方法是不能嵌套的

方法的调用

  • 有参方法的调用
public class Function{
	public int add(int x, int y){
		int z=x+y;
		return z;
	}
	public static void main(String[] args){
		Function f = new Function();
		int x = f.add(10,20);
		System.out.println(x);
		int y = fd.add(100,200);
		System.out.println(y);
	}
}
  • 有返回值的无参方法
public class FunctionAdd{
	public static int add(){
		x=100;
		y=200;
		int z=x+y;
		return z;
	}
}
  • 无返回值的无参方法
public class FunctionRect{
	void drawRect(){
		int width=10;
		int height=5;
		for(int i=0;i<height;i++){
			for(int j=0;j<width;j++){
				System.out.print("#");
			}
			System.out.println();
		}
	}
}

方法的重载

  • 方法的重载就是在同一个类中允许同时存在一个以上同名的方法

  • 方法重载的规则

    • 方法名称相同
    • 方法的参数必须不同
      • 参数个数不同 或 参数类型不同
    • 方法的返回值类型可以相同,也可以不同
  • 重载:两同,一不同(同一个类中,相同的方法名,参数类型,个数不同)

  • 方法重载

class SumFunction{
	public int getSum(int end){
		int sum=0;
		for(int i=1;i<=end;i++){
			sum+=i;
		}
		return sum;
	}
public int getSum(int start, int end){
	int sum=0;
	for(int i=start;i<end;i++){
		sum+=i;
		}
		return sum;
	}
}
  • 构造方法重载
class Employee{
	public Employee(){}
	public Employee(String_name, int age){
		name = _name;
		age = _age;
		salary = _salary;
	}
}

下列选项中,些可以与void setAge(int year,int month,int day)方法在同一个类中定义__?
A.public void setAge(){}
B.void setAge(int age){}
C.void setAge(int y,int m,int d){}
D.int setAge(Date d){}
E.int setAge(int year,int month,int day){}
F.void setage(int year,int month,int day){}

答案:ABDF

class Tool{
	public void display(int i){
		System.out.println("输出整数:"+i);
	}
	public void display(double d){
		System.out.println("输出符点数:"+d);
	}
	public void display(String args[]){
		System.out.println("输出文本:"+s);
	}
}
public classTestOverLoad{
	public static void main(String args[]){
		Tool t = new Tool();
		t.display(3);
		t.display(3.14);
		t.display("Hello,你好!");
	}
}

方法重载的多重匹配

public class Test{
	public void m1(int i){
		System.out.println("int data:"+i);
	}
	public void m1(double d){
		System.out.println("double data:"+d);
	}
	public static void main(String args[]){
		Test t = new Test();
		t.m1(3);
		t.m1(3.14);
		
		byte b = 12;	//因为没有byte方法,默认调用int
		t.m1(b);
	}
}
  • 方法的参数传递机制
    Java里方法的参数传递方式只有一种:值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响.

    下面程序演示了方法参数传递效果:

public class Main {
	public static void main(String[] args) { 
		int a = 6;
		int b =9 ;
		swap(a,b);
        System.out.println("交换结束后,a的值是"+a +",b的值是"+b);
	}
	 public static void swap(int a,int b) {
		 int temp=a;
		 a=b;
		 b=temp;
		 System.out.println("swap方法里,a的值是"+a +",b的值是"+b);
	 }
}

  • 引用类型传递案例
public class DataWrap {
	int a;
	int b;
}
public class Test {
	public static void swap(DataWrap dw){
		int tmp = dw.a;
		dw.a=dw.b;
		dw.b=tmp;
		System.out.println("swap方法里,a成员变量的值是"+dw.a
		                   +";b成员变量的值是"+dw.b);
	}
	public static void main(String[] args) {
		DataWrap dw = new DataWrap();
		dw.a=6;
		dw.b=9;
		swap(dw);
		System.out.println("交换后的,a成员变量的值是"+dw.a
		                   +";b成员变量的值是"+dw.b);
	}
}

为了更好的证明main()方法中的dw和swap()方法的中dw是两个变量,在swap()方法的最后一行增加如下代码:

//把dw直接赋值为null,让它不再指向任何有效地址
  dw = null;
  • 形参个数可变的方法
    从JDK1.5之后,Java允许定义形参个数可变的参数,从而允许为方法指定数量不确定的形参,必须在最后一个形参的类型后加三点(…),则表明该形参可以接受多个参数值。
public static void test(int a,String... books){
		System.out.println(a);
		for(String tmp: books){
			System.out.println(tmp);
		}
	}
	public static void main(String[] args) { 
		test(5,"hello","world","aaa","bbbb");
		test(5,"hello","world","aaa","bbbb","cccc");
	} 
  • 数组形参来定义方法
public static void test(int a,String[] books){}

  //调用方法传递一个数组
  test(5,new String[]{"hello","world","aaa","bbbb"});

总结:对比两种调用test()方法的代码,明显第一种形式更加简洁。最后还要指出的是,数组形式的形参可处于形参列表的[任意]位置,但个数可变的形参只能处于形参列表的[最后]位置,也就是说,一个方法中最多只能有一个个数可变的形参.

递归方法
一个方法体内调用它自身,被称为方法递归。方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。

例如有如下数学题。已知有一个数列f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n),其中n是大于0的整数,求f(10)的值。这个题可以使用递归来求得。下面程序将定义一个fn方法,用于计算f(10)的值.

public static int fn(int n) {
		if(n == 0) {
			return 1;
		} else if(n == 1){
			return 4;
		} else {
			return 2 * fn(n-1) + fn(n-2);
		}
	}
	public static void main(String[] args) {
		System.out.println(fn(10));
	}

对于fn(10),即等于2fn(9) + fn(8),其中fn(9)又等于2fn(8) + fn(7)…依次类推,最终会计算到fn(2)等于2*fn(1)+fn(0)。
因此定义递归方法时有一种最重要的规定:递归一定要向已知方向递归

7.对象的创建和使用

  • 创建对象
  • 语法格式:
    在这里插入图片描述
  • 构造器(构造方法/构造器,Constructor)
    • 具有与类相同的名称
    • 不含返回值类型
    • 不能在方法中用return语句返回一个值
    • 一般访问权限为public

在一个类中,具有上述特征的方法就是构造器。

  • 构造器的作用
    • 完成对象的创建,即完成对象的实例化
    • 一般使用构造器来完成对成员变量的初始化

默认的构造方法

  • Java语言中,每个类都至少有一个构造方法;
  • 如果类的定义者没有显式的定义任何构造方法,系统将自动提供一个默认的构造方法:
    • 默认构造方法没有参数
    • 默认构造方法没有方法体
    • 默认的构造方法:Animal(){}

所以:不编写构造方法就能用new Xxx()创建类的实例。

  • Java类中,一旦类的定义者显式定义了一个或多个构造方法,系统将不再提供默认的构造方法;

构造器的主要作用:利用构造器参数初始化对象的属性。

  • 构造器的作用

    • 完成对象的创建,即完成对象的实例化
    • 一般使用构造器来完成对成员变量的初始化
      在这里插入图片描述
  • 默认的构造器

    • 在Java中,每个类都至少要有一个构造器,如果程序员没有在类里定义构造器,系统会自动为这个类产生一个默认的访问权限为public且参数列表为空的构造器
      在这里插入图片描述
  • 一旦编程者为该定义了构造器,系统就不再提供默认的构造器

对象创建的内存模型

  • 除了8种基本数据类型的变量,其他变量都是引用类型变量、
    • 类(class)
    • 接口(interface)
    • 数组
  • 对象创建的内存模型
    Person p = new Person(“zhang”,33,“male”);
    Person q = new Person(“lisi”,44,“male”);
    在这里插入图片描述
  • 如上所示,对象的属性name、age、sex都分配在堆内存中,但对象名p、q都分配在栈内存中。p、q也称为对象的引用(reference),引用在java中是地址的同义词
  • 访问对象:在其他类中或main方法中,若想访问对象的属性或是方法必须先实例化这个类,然后通过对象名(引用)和点操作符来完成:
    对象名. 属性名;
    对象名. 方法名();
    如果在类内的方法中,访问本来的属性和方法就可以直接访问了。

在这里插入图片描述

public class character {
	String name;
	String arms;
	int fight;
	int patient;
	public character(String n,String a,int f,int p){
	name = n;
	arms = a;
	fight = f;
	patient = p;
	}
	void set(){
		System.out.println(name+"的武器为"+arms+",战斗力为"+fight+"星,耐力值为"+patient+"星.");
	}
	public static void main(String[] args){
		character char1 = new character("孙悟空","金箍棒",5,5);
		character char2 = new character("猪八戒","九齿钉耙",4,2);
		character char3 = new character("沙僧","月牙铲",3,4);
		character char4 = new character("唐僧","null",0,5);
		char1.set();
		char2.set();
		char3.set();
		char4.set();
	}
}

孙悟空的武器为金箍棒,战斗力为5星,耐力值为5星.
猪八戒的武器为九齿钉耙,战斗力为4星,耐力值为2星.
沙僧的武器为月牙铲,战斗力为3星,耐力值为4星.
唐僧的武器为null,战斗力为0星,耐力值为5星.

匿名对象

  • 创建完对象,在调用该对象方法时,也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫匿名对象
    在这里插入图片描述

  • 我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象, 如:new Person().sayHello();

  • 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。

  • 我们经常将匿名对象作为实参传递给一个方法调用。

8.垃圾回收机制

  • Java的垃圾回收机制是自动的,它保证程序健壮的主要手段,避免了由于程序员忘记回收内存而引起的内存泄漏,同时也避免了回收内存带来的代码繁琐。
  • 垃圾回收机制实际上是JVM内部运行的一个优先级比较低的后台线程,这种多线程的模式使得java具有更好的性能,完全不用程序员参与。
  • 垃圾回收机制仅仅作用于堆内存,与栈内存无关。
  • 对于程序员来说,对象何时变成垃圾呢?
    • 对象的引用被复制为null; Person p = new Person(); p=null;
    • 一次性使用的匿名对象; new Person().sayHello();
    • 超出生命周期的;如:
      for(int i=0;i<100;i++){
      Person p = new Person();
      }
      这里,变量p被实例化100次,每结束一次循环,变量p就超出生命周期,对象变为垃圾。
      在这里插入图片描述
      9.变量的作用域
  • 类变量
    • 用static修饰的成员变量,它们在类被载入时创建,只要类存在,static变量就存在
  • 实例变量
    • 类体中声明的成员变量,即非static的属性
  • 局部变量
    • 方法体中声明的变量,方法中的参数,或代码块中声明的变量,都是局部变量
    • 局部变量只在方法调用的过程中有效,方法调用结束后失效
class Employee{
	String name;
	int age;
	double salary;
	public String showName(){
		String hello = "你好";
		System.out.println(hello+name);
		return name;
	}
	public void updateName(String name2){
		name = name2;
	}
}

上述代码中name、age、salary为实例变量;hello、name2为局部变量

  • 变量初始化的顺序
    • 隐式赋予变量默认值
      • 成员变量
    • 显式赋予初始值
    • 通过构造器体赋予新值
      在这里插入图片描述

10.this关键字

  • 代表对象自身的引用
    • 一个引用
    • 指向调用该方法的当前对象
  • 通常在类的方法定义中使用
  • 用this关键字的情况
    • 方法中的变量与成员变量重名
    • 在一个构造器中,调用其他重载的构造器
    • 返回当前对象的引用

11.类的访问机制:
在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。(有一个例外)
在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。

12.对象的生命周期
在这里插入图片描述
13.package语句

  • package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。它的格式为:
    package <顶层包名>[.<子包名>]* ;
  • 应用举例:
		package p1;    //指定类Test属于包p1
		public class Test{
		        public void display(){
			System.out.println("in  method display()");
		        }
		}
  • 包对应于文件系统的目录,package语句中,用‘ .’ 来指明包(目录)的层次;
  • 包通常用小写单词,类名首字母通常大写。

14.import语句

  • 为使用定义在不同包中的Java类,需用import语句来引入所需要的类。Import语句告诉编译器到哪里去寻找类。
  • 语法格式:
    import 包名[.子包名…]. <类名 |*>
  • 应用举例:
import  p1.Test;   //import p1.*;表示引入p1包中的所有类
	public class TestPackage{
		public static void main(String args[]){
		          Test t = new Test();          //Test类在p1包中定义
		          t.display();
		}
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值