数据类型和转换
public class Main
{
public static void main(String[] args)
{
long x = 123L;
long y = 123;//自动类型提升(int --> long)
long z = 123123123123123;//错误 123123123123123理解为int类型,超出范围,要加L
float f1 = 12.3F;
float f2 = 12.3; //错误,12.3默认是double
//整型常量默认是int类型
byte b = 3;
int c = b + 1;
//浮点型型常量默认是double类型
double cc = b + 1.3;
byte x1 = 1;
short x2 = 1;
int x3 = x1 + x2;
int a = 1;
int b = 1;
boolean f = true;
String c = "123";
c = a + b + c; //输出2123
c = c + a + b + f; //输出12311true
}
}
String 与8种基本数据类型间的运算
String 可以和8种基本数据类型变量做运算,且运算只能是连接运算
类与对象
类的命名采用大驼峰
对象在内存中存在形式
属性(成员变量):随着对象的创建,存储在堆空间,new的对象放在堆空间中
局部变量:存储在栈空间中 Person p = new Person() ,p就存在栈中 args
创建的方法也压入栈中,方法用完就销毁了
栈的特点:先进后出
首先Cat cat的时候,Cat类就会被加载进JVM的方法区
其次new Cat()的时候,会在JVM堆区中开辟一个空间,用来存储对象
最后再把堆中的地址传递给引用变量cat
数组
public class Main {
public static void main(String[] args) {
//动态初始化
Student[] stu = new Student[20];
for(int i = 0; i < 20; i ++) {
stu[i] = new Student(i);
Student s = stu[i];
System.out.println(s.number);
}
//数组传递
display(stu);
//静态初始化传递,[]不能指定长度
display(new Student[]{new Student(1),new Student(2)});
}
private static void display(Student[] stu) {
for (Student student : stu) {
System.out.println(student);
}
}
}
class Student {
int number;
public Student() {}
public Student(int number) {this.number = number;}
}
克隆对象
public class Hello {
public static void main(String[] args) {
Person p = new Person();
p.name = "米兰";
p.age = 100;
mytools tools = new mytools();
Person p2 = tools.fuzhi(p);
System.out.println(p2.name + " " + p2.age);
System.out.println(p == p2);
}
}
class Person {
String name;
int age;
}
class mytools {
public Person fuzhi(Person p)
{
Person p3 = new Person();
p3.age = p.age;
p3.name = p.name;
//返回类型保持一致
return p3;
}
}
重载
规则:
- 同一个类
- 方法名相同
- 参数列表不同(参数个数或参数类型)
- 返回类型无要求
可变形参的方法
可变形参可以当成数组,方法名相同,且类型相同的数组参数不构成重载
public class Hello {
public static void main(String[] args) {
Methods me = new Methods();
System.out.println(me.sum(1,2,3,4));
//可变参数的本质是数组
//可变参数的实参可以是数组
int[] arr = {1, 2, 3};
System.out.println(me.sum(arr));
me.f("小明1", 3, 3);
me.f("小明2", 3, 3, 3);
me.f("小明3", 3, 3, 3, 3, 3);
}
}
class Methods{
// 1、int... 表示接收的是可变参数,类型是int,可以接收多个int(0个-任意多个)
// 2、使用可变参数时,可以当做数组来使用,即nums可以当成数组
// 3、一个形参列表中只能出现一个可变参数
public int sum(int... nums) {
int res = 0;
for(int i = 0; i < nums.length; i ++)
res += nums[i];
return res;
}
//细节: 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后,即只能出现一个可变参数
public void f1(String s, double... nums) {
}
public void f2(String num1, double... nums) {
}
public void f(String name, double... nums) {
int res = 0;
for(int i = 0; i < nums.length; i ++)
res += nums[i];
System.out.println(name + "的总分是" + res);
}
}
构造器
格式
[访问修饰符] 构造器名 (形参列表){
方法实现;
}
//修饰符可以为默认
细节
- 构造器无返回值
- 构造器可重载
- 每个类至少存在一个构造器,以便new对象进行调用,所有系统存在并调用默认无参构造器,JVM自动生成
- 若定义了构造器(JVM不会自动生成),默认构造器将被覆盖,需显式定义一下
- 构造器是完成对象属性的初始化,并不是创建对象,即对象先被创建
- 默认(空参)构造器与类的权限相同(public/缺省)
对象创建流程分析
Person p = new Person("小明", 20);
1、加载Person类信息,只会加载一次
2、在堆中分配空间(地址)
3、完成对象初始化
(1)、默认初始化
(2)、显式初始化
(3)、构造器初始化
(4)、返回对象在堆中的地址给p
public class Account {
private String name;
private double balance=50;
private String pwd;
//Account类的一个构造器
public Account (String name,double balance,string pwd){
//构造器的实现---初始化对象
this.name = name;
this.balance = balance;
this.pwd = pwd;
}
class Test{
public static void main(String[] args) {
//创建对象(构造器完成该对象初始化)
Account account01 = new Account("Yaoayo",20,"123456");
}
this介绍
this:Java虚拟机(JVM)会给每个对象分配一个this,代表当前对象
可以理解成一个隐藏属性,每new一个对象,就会在堆内存中分配一个空间(存在一个地址address),this的值就是对象在堆内存中的地址(address),指向这个对象(两个地址是相同的即this的值等于address)。可以在构造器和实例对象输出hashCode,看是否相同
this依赖对象,有对象才能用this,所以在static方法中,不能使用this
访问属性
public class Main() {
public static void main(String args[]) {
Person p = new Person("小明", 3);
System.out.println(p.hashCode());
}
}
class Person{
String name;
int age;
public Person(String name, int age){
this.name = name;//this.name就是当前对象的属性name
this.age = age;
System.out.println(this.hashCode());
}
public void f(){
String name = "jack";
System.out.println(name);//就近原则,输出jack
System.out.println(this.name);//当前对象,输出小明
}
}
构造器中的this用来区分当前类的属性(即成员变量)和局部变量
当不写this时,都是看做局部变量,按照就近原则来查找
局部变量存储在栈中,作用范围是方法内
成员变量存储在堆中,作用范围是本类
访问成员方法
this.方法名(参数列表)
public class DogTest {
public static void main(String[] args) {
Dog dog = new Dog();
dog.run();
}
}
public class Dog {
public void jump() {
System.out.println("正在执行jump方法");
}
// 定义一个run()方法,run()方法需要借助jump()方法
public void run() {
this.jump();
//jump();
System.out.println("正在执行 run 方法");
}
}
Java 允许对象的一个成员直接调用另一个成员,可以省略 this 前缀
访问构造器(构造器复用)
1、在一个构造器中,访问本类的另外一个构造器,默认构造器首行是super();
2、this(参数列表)和super(参数列表)只能存在一个
3、this(参数列表)只能位于构造器第一行,且会覆盖super(参数列表)
4、如果一个类中声明了n个构造器,则最多有n-1个构造器可以声明有"this(形参列表)"的结构
public T(String name, int age){
this(name);
this.age = age;
}
访问修饰符
只有默认和public才能修饰类
封装
属性private,添加public的getter()、setter(),可以和构造器使用,实现业务逻辑。
继承
extends
满足is - a关系
类A:父类、超类、基类
类B:子类、派生类
细节
- 只支持单继承(一个子类只能有一个父类)
- 子类继承了父类所有的属性和方法,但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
- 子类必须调用父类的构造器, 完成父类的初始化,若父类的无参构造器被覆盖,则必须用super指定一个构造器
- super调用父类构造器和this调用本类构造器,有且只有一条,且必须位于行首
- java所有类都是Object类的子类,Object是所有类的基类
继承本质详解
首先看子类是否有该属性,没有就在堆中一层一层往上找,找到就返回
super介绍
用于访问父类(不限于直接父类)public和protected修饰的属性、方法、构造器
一个类中声明有n个构造器,最多有n-1个构造器使用了“this(形参列表)” ,那么剩下的一定使用"super(形参列表)"
super和this的比较
方法重写
规则
- 方法名和形参列表必须相同
- 子类重写方法的权限 >= 父类方法权限
- 子类方法的返回类型 <= 父类返回类型
重写与重载的比较
多态(向上转型)
当父类的引用指向子类的对象时(向上转型):
- 可以调用父类的所有成员
- 不能调用子类的特有成员
编译类型在定义对象时就确定了,不能改变,包括方法;运行类型可以改变 - 调用父类方法时,看子类是否重写
- 访问属性时,直接访问父类属性,因为属性不可以重写
调用方法看编译类型,访问属性看运行类型
向下转型
//这是向上转型
父类类型 变量名 = new 子类类型();
Animal animal = new Cat();
//这是向下转型:
子类类型 变量名 =(子类类型)父类引用
Cat cat = (Cat)animal;
- 只能强转父类的引用,不能强转父类的对象
- 要求父类的引用必须指向子类型对象
- 可以使用子类类型中所有的成员
instanceof
判断对象的运行类型是否为XX类型或XX类型的子类型
动态绑定
1、当调用对象方法的时候,该方法会和该对象的内存地址(运行类型)绑定
2、当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
Object类的方法
==
使用范围:基本数据类型、引用数据类型
基本数据类型:判断值是否相等
引用数据类型:比较两个引用变量的地址值是否相等
equals
使用范围:引用类型
默认判断地址是否相等,类中往往重写该方法,用于判断内容是否相等
对于Integer、Sting、File、Date和包装类等,它们都重写了Object类中的equals()方法,用于比较两个对象的内容是否相等
重写equals
public class test {
public static void main(String[] args) {
Person person1 = new Person("jack", 10, '男');
Person person2 = new Person("jack", 10, '男');
System.out.println(person1.equals(person2));//不重写比较地址,重写比较每个值
}
}
class Person {
private String name;
private int age;
private char gender;
//地址给了obj Object obj = new Person();
public boolean equals(Object obj) {
//判断如果比较的两个对象是同一个对象,则直接返回true
if(this == obj)
return true;
//类型判断
if(obj instanceof Person) {
//是Person才比较
//向下转型,需要得到obj的各个属性值
Person p = (Person) obj;
return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
}
return false;
}
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
toString
对于Sting、File、Date和包装类等,它们都重写了Object类中的toString()方法