Java(四)数组与类和对象

  • 六、数组(非常重要)
  • 1.定义
  • 2.遍历
  • 2.1遍历方法
  • 2.2Arrays方法
  • 3.二维数组
  • 数组小总结
  • 七、类和对象
  • 1. 定义(重要)
  • 1.1 类
  • 1.2 对象
  • 2. this关键字(重要)
  • 2.1 特点
  • 3. 构造方法(重要)
  • 3.1实现方式
  • 3.2作用
  • 4. 封装
  • 4.1包权限(重要)
  • 4.2静态成员static(重要)
  • 5.代码块
  • 5.1 静态代码块(重要)
  • 5.1同步代码块(多线程会出现)
  • 6.内部类(重要)
  • 6.1静态内部类
  • 6.2非静态/实例内部类
  • 6.3匿名内部类(不着急他的主要途径是在抽象类中)
  • 类和对象的小总结


六、数组(非常重要)

1.定义

数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。

数组类型 [] 数组名 = new 数组类型[数组长度];

数组类型 [] 数组名={元素,元素};

int[] array1 = new int[10]; // 创建一个可以容纳10个int类型元素的数组
double[] array2 = new double[5]; // 创建一个可以容纳5个double类型元素的数组
String[] array3 = new double[3]; // 创建一个可以容纳3个字符串元素的数组
//数组初始化
int[] array1 = new int[]{0,1,2,3,4,5,6,7,8,9};
double[] array2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = new String[]{"hell", "Java", "!!!"};

如果数组中存储元素类型为引用类型,默认值为null

2.遍历

  1. 数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素
  2. 下标从0开始,介于**[0, N)**之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。
    原因是在之前再说如何存储时说过,计算机寻找数据是通过地址访问,而在数组中在你定义一个恒定大小长度的数组,在内存中就会开辟与数据类型相应大小的容量,一旦发现你寻找的数据通过下标寻找不在数组范围内就会出错(报错)。)

程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址

虚拟机栈(JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。

本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的

堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。

方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域

java对象数组steam分组_System

int[] array = {1, 2, 3};
System.out.println(array[3]); // 数组中只有3个元素,
//下标一次为:0 1 2,array[3]下标越界

2.1遍历方法

通过循环遍历数组

int[]array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < 5; i++){
System.out.println(array[i]);
}

注意:在数组中可以通过 数组对象.length 来获取数组的长度

int[]array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < array.length; i++){
System.out.println(array[i]);
}

for循环的强化

int[] array = {1, 2, 3};
for (int x : array) {
System.out.println(x);
}

基本变量:基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值

引用类型变量:而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址

java对象数组steam分组_java_02


方法参数为引用类型,这就可以通过地址改动或调用数组中的元素

public static void main(String[] args) {
int[] arr = {1, 2, 3};
func(arr);
System.out.println("arr[0] = " + arr[0]);
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]);
}

2.2Arrays方法

3.二维数组

数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };

int[][] arr = {{1, 2, 3, 4},
			   {5, 6, 7, 8},
			   {9, 10, 11, 12}
				};

二维数组遍历

for (int row = 0; row < arr.length; row++) {
	for (int col = 0; col < arr[row].length; col++) {
		System.out.printf("%d\t", arr[row][col]);
	}
	System.out.println("");
}

其实就是一个特殊的一维数组。

数组小总结

1.数组是引用类型(通过地址寻找)
2.下标从0~数组长度-1
3.数组中元素类型与数组类型一致

七、类和对象

1. 定义(重要)

类是用来对一个实体(对象)来进行描述的,比如一个人(实体(对象)),但是一个人又有脖子(类),手(类),脚(类),眼睛(类)等,这样我们就对一个人进行了完整的刻画。当然人(对象)也是不同的。比如,我和你都是人,但是我们脖子或许有些不同。

1.1 类

主要描述该实体(对象)具有哪些属性(外观尺寸等)。
类中包含的内容称为类的成员。

属性主要是用来描述类的,称之为类的成员属性或者类成员变量。

方法主要说明类具有哪些功能,称为类的成员方法。

class PetDog {

public String name;//名字
public String color;//颜色
// 狗的属性
public void barks() {
System.out.println(name + ": 旺旺旺~~~");
}
// 狗的行为
public void wag() {
System.out.println(name + ": 摇尾巴~~~");
}
}
  • 一般一个文件当中只定义一个类
  • main方法所在的类一般要使用public修饰
  • public修饰的类必须要和文件名相同
  • 不要轻易去修改public修饰的类的名称

1.2 对象

new 关键字用于创建一个对象的实例. 使用 . 来访问对象中的属性和方法. 同一个类可以创建多个实例.

简单而言就是,人不同,但描述人的方式是一样的。通过不同的实例化从而进行对不同人的描述。

class PetDog {

	public String name;//名字
	public String color;//颜色
	// 狗的属性
	public void barks() {
		System.out.println(name + ": 旺旺旺~~~");
	}
	// 狗的行为
	public void wag() {
		System.out.println(name + ": 摇尾巴~~~");
		}
}
public class Main{
	public static void main(String[] args) {
		PetDog dogh = new PetDog(); //通过new实例化对象
		dogh.name = "阿黄";
		dogh.color = "黑黄";
		dogh.barks();
		dogh.wag();
		
		PetDog dogs = new PetDog();
		dogs.name = "阿黄";
		dogs.color = "黑黄";
		dogs.barks();
		dogs.wag();
	}
}

2. this关键字(重要)

在实际运用中,会出现一个方法会传入多种数据的情况,但是每个传进去的值,一定不能拿错。为了确定每个传进去的值,就用this关键字。
具体问题是

  1. 形参名不小心与成员变量名相同
  2. 多个对象都在调用相同的函数,但是这这些函数中没有任何有关对象的说明,这些函数如何知道打印的是那个对象的数据呢?

具体作用:this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。

一个时间例子:

public class Date {
	public int year;
	public int month;
	public int day;
	public void setDay(int y, int m, int d){
	//多个数据传入后根本无法确定传入的值是什么。
		year = y;
		month = m;
		day = d;
	}
	public void printDate(){
		System.out.println(year + "/" + month + "/" + day);
	}
	public static void main(String[] args) {
		// 构造三个日期类型的对象 d1 d2 d3
		Date d1 = new Date();
		Date d2 = new Date();
		Date d3 = new Date();
		// 对d1,d2,d3的日期设置
		d1.setDay(2020,9,15);
		d2.setDay(2020,9,16);
		d3.setDay(2020,9,17);
		// 打印日期中的内容
		d1.printDate();
		d2.printDate();
		d3.printDate();
	}
}

正确写法

创建一个时间对象。

public class Date {
	public int year;
	public int month;
	public int day;
	public void setDay(int year, int month, int day){
		this.year = year;
		this.month = month;
		this.day = day;
	}
	public void printDate(){
		System.out.println(this.year + "/" + this.month + "/" + this.day);
	}
}

调用

public static void main(String[] args) {
	Date d = new Date();
	d.setDay(2020,9,15);
	d.printDate();
}

2.1 特点

  1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
  2. this只能在成员方法中使用
  3. 在成员方法中,this只能引用当前对象,不能再引用其他对象
  4. this是成员方法第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收

3. 构造方法(重要)

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

3.1实现方式

  1. 名字与类名相同,没有返回值类型,设置为void也不行
  2. 一般情况下使用public修饰
  3. 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
public class Date {
	public int year;
	public int month;
	public int day;
	// 构造方法:
	public Date(int year, int month, int day){
		this.year = year;
		this.month = month;
		this.day = day;
		System.out.println("Date(int,int,int)方法被调用了");
	}
	
	public void printDate(){
			System.out.println(year + "-" + month + "-" + day);
	}
	public static void main(String[] args) {
		// 此处创建了一个Date类型的对象,并没有显式调用构造方法
		Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
		d.printDate(); // 2021-6-9
	}
}

3.2作用

构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。

特点:

  1. 名字必须与类名相同
  2. 没有返回值类型,设置为void也不行
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
  4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)(名字相同,参数列表不同,因此构成了方法重载)
  5. 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
  6. 没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法

对象空间被申请好之后,对象中包含的成员已经设置好了初始值,

数据类型

默认值

byte

0

char

‘\u0000’

short

0

int

0

long

0L

boolean

false

float

0.0f

double

0.0

reference

null

4. 封装

面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节。

举个例子说明:
我们在使用手机时我们用户只管直接去使用,无需去理解这些具体功能是如何实现的。我只需要来用。但是对于设计者而言。他们需要去将这些功能进行实现,并将这些功能装起来,无需用户去理解功能实现,只需要他们会用就可以。

4.1包权限(重要)

范围

private

default

protected

public

同一包中的同一类





同一包中的不同类

×




不同包中的子类

×

×



不同包中的非子类

×

×

×


public:可以理解为一个人的外貌特征,谁都可以看得到
default: 对于自己家族中(同一个包(同一个目录)中)不是什么秘密,对于其他人来说就是隐私了
private:只有自己知道,其他人都不知道

在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。

可以使用 import语句导入包

import java.util.*;
public class Computer {
	private String cpu; // cpu
	private String memory; // 内存
	public String screen; // 屏幕
	String brand; // 品牌---->default属性
	public Computer(String brand, String cpu, String memory, String screen) {
			this.brand = brand;
			this.cpu = cpu;
			this.memory = memory;
			
			this.screen = screen;
	}
	public void Boot(){
		System.out.println("开机~~~");
	}
	public void PowerOff(){
		System.out.println("关机~~~");
	}
	public void SurfInternet(){
		System.out.println("上网~~~");
	}
}
	public class TestComputer {
		public static void main(String[] args) {
			Computer p = new Computer("HW", "i7", "8G", "13*14");
			System.out.println(p.brand); // default属性:只能被本包中类访问
			System.out.println(p.screen); // public属性: 可以任何其他类访问
			// System.out.println(p.cpu); // private属性:只能在Computer类中访问,不能被其他类访问
	}
}

通过import 导入我们需要的包。可以通过 * 号将整个包导入,也可以将这个符号改成具体的文件名。我更建议后者。因为这个符号代表者文件下面的全部文件。我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况.

常见的包:

  1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
  2. java.lang.reflect:java 反射编程包;
  3. java.net:进行网络编程开发包。
  4. java.sql:进行数据库开发的支持包。
  5. java.util:是java提供的工具程序包。(集合类等) 非常重要
  6. java.io:I/O编程开发包。

4.2静态成员static(重要)

static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。(俗称静态区)

  1. 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
  2. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
  3. 类变量存储在方法区当中
  4. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)
public class Student{
	private String name;
	private String gender;
	private int age;
	private double score;
	private static String classRoom = "Bit306";//看清楚,这里我用的是private修饰
	// ...
}
public class TestStudent {
	public static void main(String[] args) {
		System.out.println(Student.classRoom);
	}
}

这个代码会出现编译错误。

正确的是:

public class Student{
	private String name;
	private String gender;
	private int age;
	private double score;
	private static String classRoom = "Bit306";
	
	public static String getClassRoom(){
		return classRoom;
	}
}
public class TestStudent {
	public static void main(String[] args) {
		System.out.println(Student.getClassRoom());
	}
}

5.代码块

使用 {} 定义的一段代码称为代码块。

public class Main{
public static void main(String[] args) {
	{ //直接使用{}定义,普通方法块
		int x = 10 ;
		System.out.println("x1 = " +x);
	}
	int x = 100 ;
	System.out.println("x2 = " +x);
	}
}

实例代码块。构造代码块一般用于初始化实例成员变量。

private String name;
	private String gender;
	private int age;
	private double score;
	public Student() {
		System.out.println("I am Student init()!");
	}
//实例代码块
	{
		this.name = "bit";
		this.age = 12;
		this.sex = "man";
		System.out.println("I am instance init()!");
	}

5.1 静态代码块(重要)

使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。

public class Student{
	private String name;
	private String gender;
	private int age;
	private double score;
	private static String classRoom;
//实例代码块
{
	this.name = "李思";
	this.age = 12;
	this.gender = "men";
	System.out.println("你好!");
}
// 静态代码块
static {
	classRoom = "6班";
	System.out.println("你好同学!");
}
  1. 静态代码块不管生成多少个对象,其只会执行一次
  2. 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
  3. 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行合并
  4. 实例代码块只有在创建对象时才会执行

5.1同步代码块(多线程会出现)

等待我后续文章,这里不多解释,建议先看我后面的数据结构在来阅读这方面的文章.

6.内部类(重要)

A是外部类
B是内部类

可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。(简单而言就是,在类中定义一个类,简称类中类)(调用方法在静态类中有体现)

public class A{

		class B{
		
	}
}
  1. 外部类中的任何成员都可以在实例内部类方法中直接访问
  2. 实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
  3. 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名
    称.this.同名成员 来访问
  4. 实例内部类对象必须在先有外部类对象前提下才能创建
  5. 实例内部类的非静态方法中包含了一个指向外部类对象的引用
  6. 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。
public class A{
// 成员位置定义:未被static修饰 --->实例内部类
		public class B{
		
		}
// 成员位置定义:被static修饰 ---> 静态内部类
		static class C{
		
		}
public void func(){
// 方法中也可以定义内部类 ---> 局部内部类:几乎不用
		class D{
		
		}
	}
}

6.1静态内部类

被static修饰的内部成员类称为静态内部类

public class ClassA {
	private int a;
	static int b;
	public void methodA(){
		a = 10;
		System.out.println(a);
	}
	public static void methodB(){
		System.out.println(b);
	}
	// 静态内部类:被static修饰的成员内部类
	static class ClassB{
		public void methodInner(){
		// 在内部类中只能访问外部类的静态成员
		// a = 100; // 编译失败,因为a不是类成员变量
		b =200;
		// methodA(); // 编译失败,因为methodB()不是类成员方法
		methodB();
		}
	}
	public static void main(String[] args) {
			// 静态内部类对象创建 & 成员访问
			ClassA.ClassB Class = new ClassA.ClassB();
			Class.methodInner();
		}
}

6.2非静态/实例内部类

即未被static修饰的成员内部类。

public class OutClass {
		private int a;
		static int b;
		int c;
		public void methodA(){
			a = 10;
			System.out.println(a);
		}
		public static void methodB(){
			System.out.println(b);
		}
		// 实例内部类:未被static修饰
		class InnerClass{
			int c;
			public void methodInner(){
		// 在实例内部类中可以直接访问外部类中:任意访问限定符修饰的成员
			a = 100;
			b =200;
			methodA();
			methodB();
		// 如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的
			c = 300;
			System.out.println(c);
		// 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
			OutClass.this.c = 400;
			System.out.println(OutClass.this.c);
		}
	}
	public static void main(String[] args) {
// 外部类:对象创建 以及 成员访问
		OutClass outClass = new OutClass();
		System.out.println(outClass.a);
		outClass.methodA();

实例内部类的访问

// 要访问实例内部类中成员,必须要创建实例内部类的对象
// 而普通内部类定义与外部类成员定义位置相同,因此创建实例内部类对象时必须借助外部类
// 创建实例内部类对象
		OutClass.InnerClass innerlass1 = new OutClass().new InnerClass();
// 上述语法比较怪异,也可以先将外部类对象先创建出来,然后再创建实例内部类对象
		OutClass.InnerClass innerClass2 = outClass.new InnerClass();
		innerClass2.methodInner();
}

6.3匿名内部类(不着急他的主要途径是在抽象类中)

类和对象的小总结

1.类就是描述物体的一种集合,类中定义的方法以及成员是具体描述这个物体的固有属性(称其为对象)(如动物这个大类他是一个抽象的描述,并不具体,而动物有很多他们都有不同的名字,体型,身高,叫声,比如狗,猫,鸟,老虎…这些动物的描述方式各有不同)

2.用{}包裹的就是代码块,用static修饰的是静态代码块

3.内部类就是通过在一个类中再次定义一个的方式,通常分为非静态内部类,静态内部类(用static修饰的静态的内部类。)

4.内部类调用通常:(非静态内部类 ) **外部类.内部类 xxx=外部类.new 内部类();**进行实例化。(静态内部类)**外部类.内部类 xxx=new 外部类.内部类();**进行实例化。