类的成员之——属性
语法格式:
public class Student{
public String name;
private int age = 18;
}
属性可以赋值的位置
①默认初始化
②显式初始化/⑤在代码块中赋值
③构造器中初始化
④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
执行的先后顺序:① - ② / ⑤ - ③ - ④
属性(成员变量)与局部变量
1.相同点:
1.1 定义变量的格式:数据类型 变量名 = 变量值
1.2 先声明,后使用
1.3 变量都有其对应的作用域
2.不同点:
2.1 在类中声明的位置的不同
属性:直接定义在类的一对{}内
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
2.2 关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符:private、public、缺省、protected --->封装性
局部变量:不可以使用权限修饰符。
2.3 默认初始化值的情况:
属性:类的属性,根据其类型,都有默认初始化值。
整型(byte、short、int、long):0
浮点型(float、double):0.0
字符型(char):0 (或'\u0000')
布尔型(boolean):false
引用数据类型(类、数组、接口):null
局部变量:没有默认初始化值。 意味着,我们在调用局部变量之前,一定要显式赋值。
特殊:形参在调用时,我们赋值即可。
2.4 在内存中加载的位置:
属性:加载到堆空间中 (非static)
局部变量:加载到栈空间
类的成员之——方法
方法的声明格式
说明
1 权限修饰符:Java规定的4种权限修饰符:private、public、缺省、protected
2 返回值类型: 有返回值 vs 没有返回值
2.1 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。
2.2 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。
3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
4 形参列表: 方法可以声明0个,1个,或多个形参。
4.1 格式:数据类型1 形参1,数据类型2 形参2,...
4.2 我们定义方法时,该不该定义形参?(具体问题具体分析)
5 方法体:方法功能的体现。
6 return关键字的使用:
6.1 使用范围:使用在方法体中
6.2 作用:① 结束方法
② 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。
6.3 注意点:return关键字后面不可以声明执行语句
7 方法的使用中,可以调用当前类的属性或方法
7.1 特殊的:方法A中又调用了方法A:递归方法。
7.2 方法中,不可以定义方法。
方法的重载
定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
遵循原则:两同一不同原则:同一个类、相同方法名 ;参数列表不同:参数个数不同,参数类型不同
Test :比较三个数,输出其中最大数(运用方法重载,可满足不同类型)
class GetMax{
public static void main(String[] args) {
GetMax test = new GetMax();
System.out.println(test.getMax(11, 22, 33));
}
public int getMax(int i,int j,int c){
int max = (i > j) ? i : j;
return (max > c) ? max : c;
}
public double getMax(double i,double j,double c){
double max = (i > j) ? i : j;
return (max > c) ? max : c;
}
}
方法的可变个数的形参(jdk 5.0新增的内容)
1 可变个数形参的格式:数据类型 ... 变量名
2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
5 可变个数形参在方法的形参中,必须声明在末尾
6 可变个数形参在方法的形参中,最多只能声明一个可变形参。
public class MethodArgs {
public static void main(String[] args) {
MethodArgs test = new MethodArgs();
test.print(12);
test.print("12");
test.print("12","13","14");
//等同于上边
test.print(new String[]{"12","13","14"});
}
public void print(int i){
System.out.println("输入的【" + i + "】为int类型");
}
public void print(String s){
System.out.println("输入的【" + s + "】为String类型");
}
public void print(String ... str){
for (int i = 0; i < str.length; i++) {
System.out.println("输入的【" + str[i] + "】为String...类型");
}
}
/*不能与上一个方法同时存在
public void print(String[] str){
System.out.println("输入为String...类型");
}*/
}
// public void print(String ...str,int i){ //可变个数形参必须放在末尾
public void print(int i,String ...str){
System.out.println("可变个数形参必须放在末尾");
}
方法参数的值传递机制(值传递)
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
* 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
class ValueTransfer{
public static void main(String[] args) {
Student1[] arr = new Student1[10];//声明Student1类型的数组
for (int i = 0; i < arr.length; i++) {
arr[i] = new Student1();//给数组元素赋值
arr[i].score = (int)(Math.random() * (100-0 +1) +0);//给Student1对象的属性(成绩)赋值(0-100的随机数)
}
//按成绩冒泡排序
ValueTransfer test = new ValueTransfer();
for (int i = 0; i < arr.length -1; i++) {
for (int j = 0; j < arr.length -1 -i; j++) {
//如果需要换序,交换的是数组的元素:Student对象!!!(不要把成绩交换了)
if (arr[j].score > arr[j+1].score){
// test.swap(j,j+1); //所以属于基本数据类型 为数据值传递 不能通过中间变量交换(比如a=10,b=a,b=20,a=?还是10)
// test.swap(arr[i],arr[i+1]);//数组的元素是基本数据类型 是数据值传递
test.swap(arr,j,j+1);//引用数据类型是地址值传递
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i].score);
}
}
/**
* @description 交换数组中指定位置的二个元素的值
* @author ALvin
* @date 2022年1月11日10:18:38
* param
*/
public void swap(int i,int j){
int temp = i;
i = j;
j = temp;
}
public void swap(Student1 i,Student1 j){
Student1 temp = i;
i = j;
j = temp;
}
public void swap(Student1[] st,int i,int j){
Student1 temp = st[i];
st[i] = st[j];
st[j] = temp;
}
}
class Student1{
int score;//成绩
}
递归方法
递归方法:一个方法体内调用它自身
class Recursion{
public static void main(String[] args) {
Recursion test = new Recursion();
System.out.println(test.getSum(3));
}
public int getSum(int n){
if(n == 1){
return 1;
}else {
return n * getSum(n-1);
}
}
}
类的构造方法(构造器)
作用:1.创建对象 2.初始化对象的信息
特征:1.它具有与类相同的名称 2.它不声明返回值类型。(与声明为void不同) 3.不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值
说明:
1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.定义构造器的格式:权限修饰符 类名(形参列表){}
3.一个类中定义的多个构造器,彼此构成重载
4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
5.一个类中,至少会有一个构造器。
public class Java1 {
public static void main(String[] args) {
//创建类的对象:new + 空参构造器
Person p = new Person();
p.setName("张三");
p.eat();
p.study();
//创建类的对象:new + 有参构造器
Person p1 = new Person("李四");
p1.eat();
p1.study();
}
}
class Person{
private String name;//名字(private只能在本类中使用)
private int age;//年龄
//空参构造
public Person(){}
//有参构造
public Person(String name) {
this.name = name;
}
//定义属性的get,set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//方法
public void eat(){
System.out.println(name + "吃饭");
}
public void study(){
System.out.println(name+ "学习");
}
}
类的成员之——代码块 (或初始化块)
1. 代码块的作用:用来初始化类、对象
2. 代码块如果有修饰的话,只能使用static.
3 分类:静态代码块 vs 非静态代码块
4. 静态代码块
>内部可以有输出语句
>随着类的加载而执行,而且只执行一次
>作用:初始化类的信息
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行要优先于非静态代码块的执行
>静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
5. 非静态代码块
>内部可以有输出语句
>随着对象的创建而执行
>每创建一个对象,就执行一次非静态代码块
>作用:可以在创建对象时,对对象的属性等进行初始化
>如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
6. 执行顺序:由父及子 静态先行
public class BlockTest {
public static void main(String[] args) {
Animal a = new Animal();
System.out.println(a);
}
}
class Animal{
String name;
int age;
static String desc = "动物"; //静态属性 全类通用
//构造器
public Animal(){}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
//非静态代码块
{
name = "小狗";
age = 3;
desc = "我是一只小狗";
show();
toString();
}
//静态代码块
static {
//静态代码块不能调用非静态变量
// name = "小狗";
// age = 3;
desc = "我是一只小狗1";
show();
// toString; //静态代码块不能调用非静态方法
System.out.println(desc);
}
//方法
public String toString(){
return "name=" + name + ",age=" +age;
}
public static void show(){
System.out.println("Static方法");
}
}
//执行结果:
//Static方法
//我是一只小狗1
//Static方法
//name=小狗,age=3
类的成员之——内部类
内部类的定义和使用规范
1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
2. 内部类的分类:成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)
3. 成员内部类:
一方面,作为外部类的成员:
>调用外部类的结构
>可以被static修饰
>可以被4种不同的权限修饰
另一方面,作为一个类:
> 类内可以定义属性、方法、构造器等
> 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
> 可以被abstract修饰
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类):
Animal.Dog dog = new Animal.Dog();
dog.eat();
dog.show();
//创建Pig实例(非静态的成员内部类):
Animal anm = new Animal();
anm.name = "八戒";
Animal.Pig pig = anm.new Pig();
pig.name = "二白";
pig.eat();
pig.show("佩奇");
}
}
class Animal{
String name;
public void eat(){
System.out.println("进食");
}
//静态成员内部类
static class Dog{
public void eat(){
System.out.println("小狗吃饭");
}
public void show(){
System.out.println("小狗");
// Animal.this.eat(); //静态类中不能引用非静态方法
eat();
}
}
//非静态成员内部类
class Pig{
String name;
public void eat(){
System.out.println("小猪吃饭");
}
public void show(String name){
System.out.println("小猪");
Pig.class.getClass();
Animal.this.eat();
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的形参
System.out.println(Animal.this.name);//外部类的形参
}
}
}
//执行结果
/*
小狗吃饭
小狗
小狗吃饭
小猪吃饭
小猪
进食
佩奇
二白
八戒
*/
4. 局部内部类: 4.1 只能在声明它的方法或构造器或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
4.2 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
4.3 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
4.4 局部内部类可以使用外部类的成员,包括私有的。
4.5 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
4.6 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
4.7 局部内部类不能使用static修饰,因此也不能包含静态成员
public class InnerClassTest1 {
public static void main(String[] args) {
Person1 p = new Person1();
p.name = "老李";
p.eat();
}
}
class Person1{
String name;
{
//定义在代码块中的局部内部类
class CC{
public void disPlay(){
System.out.println("定义在代码块中的局部内部类");
System.out.println(name);
}
}
}
public Person1(){
//定义在构造器的局部内部类
class AA {
public void disPlay1() {
System.out.println("定义在构造器中的局部内部类");
System.out.println(name);
}
}
}
public void eat(){
int num = 10;
System.out.println("吃饭");
//局部内部类(方法中)
// public class BB { //不能使用 public,protected,缺省,private 来修饰
class BB {
public void disPlay(String name) {
System.out.println("定义在方法中的局部内部类");
System.out.println(name);//方法的形参
System.out.println(Person1.this.name);//外部类的name属性
System.out.println(num + 1);//调用外部方法的局部变量
}
}
//先声明,后使用
BB bb = new BB();
bb.disPlay("老王");
}
}
//执行结果
/*
吃饭
定义在方法中的局部内部类
老王
老李
11
*/
5. 重点关注如下的3个问题
5.1 如何实例化成员内部类的对象
5.2 如何在成员内部类中区分调用外部类的结构
5.3 开发中局部内部类的使用
拓展 ——UML类图
说明:本篇文章部分内容和图片引用尚硅谷官网内容,特此说明。@尚硅谷官网地址