Java是一种计算机程序设计语言,所有的计算机程序一直都是围绕着两件事在进行的(如何表示和存储数据;基于这些数据都有什么操作行为,实现什么功能),程序设计就是用某种语言编写代码来完成这两件事,所以程序设计语言又称为编程语言。
如何表示数据和存储数据
* 基于数据类型的变量和常量:表示和存储一个个独立的数据。
* 对象:表示和存储与某个具体事物相关的多个数据(如一个学生的姓名、年龄、性别、学号等等)。
* 数据结构:表示和存储一组数据,数据结构有数组、链表、栈、队列、散列表、树......
基于这些数据能实现哪些功能
* 数据的输入输出
* 数据间的赋值运算、算术运算、比较运算、逻辑运算......
* 基于一组数据的统计分析、查找元素、遍历......
程序设计方法分为面向过程和面向对象两种
面向过程的程序设计思想(Process-Oriented Programming),简称POP
- 面向过程的程序设计思想关注的焦点是操作数据的步骤,如果某段代码被多次使用,那么就可以将这个过程抽象为一个函数,可以简化代码,减少冗余,也便于维护。
- 代码的结构是以函数为组织单位,独立于函数之外的数据称为全局数据,在函数内部的数据称为局部数据
.面向对象的程序设计思想(Object Oriented Programming),简称OOP
- 面向对象的程序设计思想关注的焦点是类,在计算机程序设计过程中,参照现实中的事物,将事物的属性特征、行为特征抽取出来,用一个类来表示。某一个事物的具体个体称为示例或对象
- 代码结构是以类为组织单位。每种事物都具备自己的属性(属性是用来表示和存储数据的,在类中用成员变量来表示)和行为/功能(即对数据的操作,在类中用成员方法表示)
如对于 学生类,它的实例可以是一个名叫张三的学生、也可以是名叫李四的学生
关键字:class
[修饰符] class 类名 {
}
如
public class Student {
}
学生类
属性:姓名,年龄,性别
行为:学习,睡觉
public class Student { // 类名为Student
String name ; // 姓名属性
int age ; // 年龄属性
String sex ; // 性别属性
public void study() {
System.out.println(name + " 在学习.....");
}
public void sleep() {
System.out.println(name + " 在睡觉.....");
}
}
手机类
属性:价格,品牌,颜色
行为:打电话,玩游戏,发信息
public class Phone { // 手机类
String brand ; // 品牌属性
double price ; // 价格属性
String color ; // 颜色属性
public void call() { // 打电话行为
System.out.println("打电话......");
}
public void playGame() { // 玩游戏属性
System.out.println("玩游戏......");
}
public void sendMessage() { // 发信息行为
System.out.println("发信息.....");
}
}
- 在使用一个类时,我们必须对该类进行实例化,即创建该类的对象
创建对象的格式:类名 对象名 = new 类名();- 如何使用类中的成员变量
对象名.变量名- 如何使用类中的成员方法
对象名.方法名([参数])
类名 对象名 = new 类名();
案例:创建学生对象
public class StudentTest {
public static void main(String[] args) {
// 创建学生类对象
Student student = new Student();
// 调用其成员变量并赋值
student.name = "张三" ;
student.age = 21 ;
student.sex = "男" ;
// 调用成员方法
student.sleep();
student.study();
System.out.println(student);
}
}

对象名中存储的是对象的地址,对象是引用数据类型cn.pdsu.edu.Student@4554617c”也不是对象的地址,因为Java是对程序员隐藏内存地址的,不暴露内存地址信息,所以打印对象时不直接显示内存地址,而是JVM帮你调用了对象的toString方法,将对象的基本信息转换为字符串并返回,默认toString方法返回的是“对象的运行时类型@对象的hashCode值的十六进制值”,程序员可以自己改写toString方法的代码
[修饰符] 数据类型 成员变量名;
如:
String name;
int age;
String sex;
- 位置要求:成员变量必须定义在类中,方法外
- 类型要求:可以是任何类型的,包括基本数据类型,引用数据类型
- 修饰符:如public、static、protected、private…
- 其中static将变量分为两大类:静态变量和非静态变量,其中静态变量又称为类变量,非静态变量又称为实例变量或属性。
实例变量的特点
实例变量的值是属于某个对象的
- 必须通过对象才能访问实例变量
- 每个对象的实例变量的值是独立的
实例变量有默认值(对应数据类型的默认值)
访问实例变量:对象名.实例变量
案例:
public class StudentDemo {
public static void main(String[] args) {
Student s = new Student() ;
Student s1 = new Student() ;
s.name = "张三" ;
s.age = 21 ;
s.sex = "男" ;
System.out.println("s.name = " + s.name);
System.out.println("s.age = " + s.age);
System.out.println("s.sex = " + s.sex);
System.out.println("s1.name = " + s1.name);
System.out.println("s1.age = " + s1.age);
System.out.println("s1.sex = " + s1.sex);
}
}


对象头
Mark Word:记录了和当前对象有关的GC、锁等信息。
指向类的指针:每一个对象需要记录它是由哪个类创建出来的,而Java对象的类数据保存在方法区,指向类的指针就是记录创建该对象的类数据在方法区的首地址。该指针在32位JVM中的长度是32bit,在64位JVM中长度是64bit。
数组长度(只有数组对象才有)
实例数据
- 即实例变量的值
对齐填充
- 因为JVM要求Java对象占的内存大小应该是8bit的倍数,如果不满足该大小,则需要补齐至8bit的倍数,没有特别的功能。
方法调用的语法格式:对象.非静态方法([实参列表])
方法的特殊参数
形参是类类型(引用数据类型)举例:
class TestStudent {
public static void main(String[] args) {
Student student = new Student();
student.name = "张三" ;
student.age = 15 ;
print(student);
}
public static void print(Student s) {
System.out.println(s.name);
System.out.println(s.age);
s.study();
}
}
public class Student { // 类名为Student
String name ; // 姓名属性
int age ; // 年龄属性
public void study() {
System.out.println(name + " 在学习.....");
}
public void sleep() {
System.out.println(name + " 在睡觉.....");
}
}

形参是可变参数
在JDK1.5之后,在定义一个方法时,形参的类型需要确定,但是形参的个数可以是不确定的,可以考虑使用可变参数 可变参数的格式:参数类型… 参数名
可变参数的特点和要求:
- 一个方法最多只能有一个可变参数
- 如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个,前面传的参数默认给对应的参数赋值
- 在声明它的方法中,可变参数当成数组使用,个数范围从0到无穷大
- 举例:
- 先定义一个方法print(int[] arr) 参数列表是int数组,
- 再定义一个方法print(int… arr) 参数列表为可变参数 会报错,不是方法的重载,而是同一个方法,可变参数等同于数组

案例:
public class Demo1 {
public static void main(String[] args) {
int[] arr = {11 , 22 , 33 , 44 , 55} ;
print(100 , arr);
print(arr);
}
public static void print(int j , int... arr) {
System.out.println("j = " + j);
for (int i = 0 ; i < arr.length ; i ++) {
System.out.println(arr[i]);
}
}
public static void print(int... arr) {
for (int i = 0 ; i < arr.length ; i ++) {
System.out.println(arr[i]);
}
}
}

参数类型为命令行参数通过命令行给main方法的形参传递的实参称为命令行参数
public class Demo2 {
public static void main(String[] args) {
System.out.println(args);
System.out.println(args.length);
for (int i = 0 ; i < args.length ; i ++) {
System.out.println("第" + (i+1) + "个参数的值是:" + args[i]);
}
}
}

在IDEA中配置运行参数


配置参数后再次运行

public class Demo3 {
public static void main(String[] args) {
int a = 4 ;
int b = 8 ;
System.out.println("交换前a = " + a + " , b = " + b);
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("方法内 :交换后a = " + a + " , b = " + b);
}
}

可以看到,即使在调用过交换方法后,再输出a、b仍为交换前的顺序。这是因为实参a、b是基本数据类型,传递给实参的是数据的"副本",在调用完后,a、b的值不会发生任何的改变
案例:
public class Demo4 {
public static void main(String[] args) {
int[] arr1 = {1 , 2 , 3} ;
int[] arr2 = {3 , 2 , 1} ;
System.out.println("交换前的arr1=" + arr1 + " , 交换前的arr2=" + arr2);
swap(arr1 , arr2);
System.out.println("交换后的arr1=" + arr1 + " , 交换后的arr2=" + arr2);
}
public static void swap(int[] arr1 , int[] arr2) {
int[] temp = arr1 ;
arr1 = arr2 ;
arr2 = temp ;
System.out.println("方法内:交换后的arr1=" + arr1 + " , 交换后的arr2=" + arr2);
}
}

public class Demo4 {
public static void main(String[] args) {
int[] arr1 = {1 , 2 , 3} ;
int[] arr2 = {3 , 2 , 1} ;
System.out.print("arr1 : ");
for (int i = 0 ; i < arr1.length ; i ++) {
System.out.print(arr1[i] + " , ");
}
System.out.print("arr2 : ");
for (int i = 0 ; i < arr2.length ; i ++) {
System.out.print(arr1[i] + " , ");
}
System.out.println();
swap(arr1 , arr2);
System.out.print("arr1 : ");
for (int i = 0 ; i < arr1.length ; i ++) {
System.out.print(arr1[i] + " , ");
}
System.out.print("arr2 : ");
for (int i = 0 ; i < arr2.length ; i ++) {
System.out.print(arr1[i] + " , ");
}
}
public static void swap(int[] arr1 , int[] arr2) {
arr1[1] = 100 ;
arr2[1] = 50 ;
System.out.print("方法内arr1 : ");
for (int i = 0 ; i < arr1.length ; i ++) {
System.out.print(arr1[i] + " , ");
}
System.out.print("方法内arr2 : ");
for (int i = 0 ; i < arr2.length ; i ++) {
System.out.print(arr1[i] + " , ");
}
System.out.println();
}
}


案例:
public class Car {
/**
* 车名
*/
String name ;
/**
* 车的颜色
*/
String color ;
public void run() {
System.out.println(name + "在路上跑...");
}
}
class CarTest {
public static void main(String[] args) {
Car car = new Car();
car.name = "比亚迪" ;
car.color = "黑色" ;
car.run();
}
}


public class Car {
/**
* 车名
*/
String name ;
/**
* 车的颜色
*/
String color ;
public void run() {
System.out.println(name + "在路上跑...");
}
}
class CarTest {
public static void main(String[] args) {
Car car1 = new Car();
Car car2 = new Car();
car1.name = "比亚迪" ;
car1.color = "黑色" ;
car1.run();
}
}


对于对象,每次创建后,所有成员变量都是默认值,如果我们需要对其进行赋值操作,需要挨个进行,太麻烦了。我们能不能在创建对象时,直接为当前对象的某个或所有成员变量直接赋值呢。
[修饰符] class 类名 {
[修饰符] 构造器名() {
}
[修饰符] 构造器名(参数列表) {
}
}
- 构造器在每次创建对象时都会执行
- 构造器的名字必须和它所在类的类名相同
- 构造器没有返回值,不需要返回值类型,也不需要void
- 如果在定义类时没有提供构造器,系统会默认给一个无参构造器,并且该构造器的修饰符默认与类的修饰符相同。但是如果在定义类时提供了有参构造器,那么系统将不再提供无参构造器,如果要使用需要自己定义。
- 构造器是可以重载的,可以是无参、一参、两参、多参
- 构造器的修饰符只能是权限修饰符
案例:
public class Teacher {
String name ;
int age ;
String sex ;
public Teacher() {
}
public Teacher(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public void getInfo() {
System.out.println("姓名:" + this.name + ", 年龄:" + this.age + ", 性别:" + this.sex);
}
}
class TeacherTest {
public static void main(String[] args) {
Teacher t1 = new Teacher();
Teacher t2 = new Teacher("张三" , 30 , "男");
t1.getInfo();
t2.getInfo();
}
}

声明位置和方式
在内存中存储的位置不同
生命周期
作用域
修饰符
默认值
没有名字的对象即为匿名对象
调用方法,仅仅只调用一次的时候
匿名对象可以作为实际参数传递
节省代码
匿名对象调用完毕就是垃圾。可以被垃圾回收器回收。
案例:
public class User {
String name ;
int age ;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void getInfo() {
System.out.println("User{" +
"name='" + name + '\'' +
", age=" + age +
'}');
}
}
class TestUser {
public static void main(String[] args) {
User user = new User("张三" , 25);
method(new User("李四" , 20)); // 匿名内部类
method(user);
}
public static void method(User user) {
user.getInfo() ;
}
}

对象数组,首先要创建数组对象本身,确定数组的长度,然后再创建每一个元素对象,如果不创建,数组元素的默认值就是null,容易出现空指针异常NullPointerException。
案例:
public class Person {
String name ;
int age ;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sleep() {
System.out.println(name + "在睡觉......");
}
public void eat() {
System.out.println(name + "在吃东西......");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class PersonTest {
public static void main(String[] args) {
Person[] pArr = new Person[3] ;
Person p1 = new Person("张三" , 20);
Person p2 = new Person("李四" , 21);
Person p3 = new Person("王五" , 22);
pArr[0] = p1 ;
pArr[1] = p2 ;
pArr[2] = p3 ;
for (int i = 0 ; i < pArr.length ; i ++) {
System.out.println(pArr[i]);
}
}
}

避免了的重名,将类创建在包里,类的全路径名称为包名.类名
控制某些类型或成员的可见范围
分类组织管理不同类型的类
- 例如:
java.lang----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread等,提供常用功能
java.net----包含执行与网络相关的操作的类和接口。
java.io ----包含能提供多种输入/输出功能的类。
java.util----包含一些实用工具类,如集合框架类、日期时间、数组工具类Arrays,文本扫描仪Scanner,随机值产生工具Random。
关键字:package
package 包名;
注意:
包的命名规范和习惯:
注意:只有public的类才能被跨包使用
如:java.util.Scanner sc = new java.util.Scanner(System.in) ;
使用import语句导包后可简化书写
import语句语法格式
import 包名.类名;import 包名.*;使用java.lang包下的类,不需要import语句,就直接可以使用简名称
import语句必须在package下面,class的上面
当使用两个不同包的同名类时,例如:java.util.Date和java.sql.Date。一个使用全名称,一个使用简名称
举例:
package cn.pdsu.edu;
import java.util.Date;
import java.util.Scanner;
public class Demo1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in) ;
Student student = new Student() ; // 同一个包下的类
Date date = new Date() ;
java.sql.Date date1 = new java.sql.Date(1) ;
}
}