Avoid These Hidden Java Pitfalls: Object Comparison, Generics, and CGLIB Proxy Gotchas

This article reveals common Java pitfalls—from using Objects.equals versus ==, ternary operator type conversion, generic type mismatches, Set deduplication, BeanUtils property copying, to CGLIB proxy quirks—and provides concrete analysis and practical avoidance techniques for each case.

21CTO
21CTO
21CTO
Avoid These Hidden Java Pitfalls: Object Comparison, Generics, and CGLIB Proxy Gotchas

1. Object Comparison Pitfalls

Before JDK 1.7, comparing wrapper types with == works because the compiler automatically unboxes the constant to the primitive type. After JDK 1.7, Objects.equals is recommended, but it does not perform automatic unboxing, leading to different results.

Short shortValue = (short)12345;
System.out.println(shortValue == 12345); // true
System.out.println(Objects.equals(shortValue, 12345)); // false

The bytecode shows the compiler inserts sipush and if_icmpne for primitive comparison, while Objects.equals forces boxing, causing mismatched types.

In Java, integer literals default to int and floating‑point literals default to double .

To avoid the issue, use explicit primitive literals or the diamond syntax when constructing objects.

Short shortValue = (short)12345;
System.out.println(shortValue == (short)12345); // true

1.2 Problem Analysis

The compiler treats the constant as int, automatically converting it to Integer when Objects.equals is used, so the comparison fails for mismatched wrapper types.

1.3 Avoidance Method

Prefer explicit primitive literals.

Use Objects.equals only when both operands are of the same wrapper type.

2. Ternary Expression Type Conversion

A ternary expression returns the highest‑priority primitive type when one branch yields a primitive result and the other yields a wrapper object. If the wrapper is null, the JVM attempts to unbox it, causing NullPointerException.

boolean condition = false;
Double value1 = 1.0D;
Double value3 = null;
Double result = condition ? value1 * value2 : value3; // NPE

Bytecode shows the doubleValue() call on a null reference.

2.2 Problem Analysis

According to the ternary conversion rules, the expression’s result type becomes double, forcing unboxing of value3 and triggering the exception.

2.3 Avoidance Method

Replace ternary expressions with explicit if‑else blocks when arithmetic and wrapper types are mixed.

Use primitive variables in the ternary expression.

double result;
if (condition) {
    result = value1 * value2;
} else {
    result = value3; // value3 must be primitive
}

3. Generic Object Assignment

Assigning List<UserDO> to List<UserVO> via a raw PageDataVO constructor compiles due to legacy raw‑type compatibility, but it bypasses type checking and can leak sensitive fields.

return new PageDataVO(totalCount, dataList); // raw type

Using the diamond operator forces proper generic inference:

return new PageDataVO<>(totalCount, dataList);

3.2 Problem Analysis

Because BaseDO uses a generic T for id, the getter returns Object, and ClassUtils.isAssignable fails when copying to a Long field.

3.3 Avoidance Method

Instantiate generic classes with diamond syntax.

Prefer manual property copying for a few fields.

4. Set Deduplication

Using HashSet<City> without overriding hashCode and equals stores duplicate city objects because each instance has a distinct identity.

private static class City {
    private String code;
    private String name;
}

Override these methods to deduplicate based on code:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    return Objects.equals(code, ((City) obj).code);
}
@Override
public int hashCode() {
    return Objects.hashCode(code);
}

4.3 Avoidance Method

Use List when data is guaranteed unique.

Use Map<String, City> for deduplication based on a key.

Always override hashCode and equals for objects stored in a Set.

5. BeanUtils Property Copying

Copying properties between UserDO and UserVO fails for the id field because the generic base class returns Object from getId(), and the type‑check rejects assignment to Long.

BeanUtils.copyProperties(userDO, userVO);

Manual copying works because the actual value is retrieved and assigned directly.

5.3 Avoidance Method

Do not rely blindly on third‑party utilities; verify their behavior.

Manually copy a small number of fields when performance or correctness is critical.

6. CGLIB Proxy Field Issues

When a Spring service class contains a final method (e.g., getSuperUser()) and a non‑final setter, CGLIB creates a proxy that overrides the setter but not the getter. The proxy holds a separate instance, so the getter reads a null field.

public final User getSuperUser() { return this.superUser; }
public void setSuperUser(User u) { this.superUser = u; }

Similarly, public fields are not initialized in the proxy instance, leading to NullPointerException when accessed.

6.3 Avoidance Method

Avoid final on classes or methods that need to be proxied.

Prefer private fields with public getters/setters.

Use static constants for immutable data.

7. Public Field Proxy Issues

Public mutable fields are not initialized in CGLIB proxies, causing them to appear null at runtime.

public final User superUser = new User(0L, "admin", "超级用户");

Accessing userService.superUser from a proxied bean returns null.

7.3 Avoidance Method

Define immutable data as public static final constants.

Keep fields private and expose them via getters.

Follow JavaBean conventions: no public instance fields.

Afterword

Human reasoning often relies on analogies, which can both accelerate learning and create fixed‑mindset traps. Recognizing these patterns helps avoid misjudgments when confronting new technical challenges.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaspringGenericsbest practicesCollectionscglib
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.