You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by li...@apache.org on 2023/06/18 18:24:54 UTC

[arrow] branch main updated: GH-15187: [Java] Made `reader` initialization lazy and added new `getTransferPair()` function that takes in a `Field` type (#34424)

This is an automated email from the ASF dual-hosted git repository.

lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new c3eaf4cb29 GH-15187: [Java] Made `reader` initialization lazy and added new `getTransferPair()` function that takes in a `Field` type (#34424)
c3eaf4cb29 is described below

commit c3eaf4cb2904a45e8b8029eb6ee5b67be9464e0d
Author: rtadepalli <10...@users.noreply.github.com>
AuthorDate: Sun Jun 18 14:24:47 2023 -0400

    GH-15187: [Java] Made `reader` initialization lazy and added new `getTransferPair()` function that takes in a `Field` type (#34424)
    
    ### Rationale for this change
    This PR closes #15187. `FieldReader` is being allocated directly in the constructor today, and this PR changes it such that the initialization becomes lazy. Additionally, a new function `getTransferPair(Field, Allocator)` is introduced so that a new `Field` method is not constructed each time `getTransferPair` is called on the Vector.
    
    ### What changes are included in this PR?
    
    1. Introduce a new `getTransferPair` method.
    2. Make initializing `FieldReader` lazy.
    
    ### Are these changes tested?
    
    Yes, some tests have been added to verify these changes.
    
    ### Are there any user-facing changes?
    
    I am not 100% sure if there are any user facing changes.
    
    There should not be any breaking changes.
    * Closes: #15187
    
    Authored-by: Ramasai <ra...@gmail.com>
    Signed-off-by: David Li <li...@gmail.com>
---
 .../apache/arrow/vector/BaseFixedWidthVector.java  |  8 ++++++
 .../org/apache/arrow/vector/BaseValueVector.java   | 32 ++++++++++++++++++++++
 .../java/org/apache/arrow/vector/BigIntVector.java | 30 +++++++++++++-------
 .../java/org/apache/arrow/vector/BitVector.java    | 31 +++++++++++++--------
 .../org/apache/arrow/vector/DateDayVector.java     | 30 +++++++++++++-------
 .../org/apache/arrow/vector/DateMilliVector.java   | 30 +++++++++++++-------
 .../org/apache/arrow/vector/Decimal256Vector.java  | 30 +++++++++++++-------
 .../org/apache/arrow/vector/DecimalVector.java     | 30 +++++++++++++-------
 .../org/apache/arrow/vector/DurationVector.java    | 28 +++++++++++++------
 .../apache/arrow/vector/ExtensionTypeVector.java   |  2 +-
 .../apache/arrow/vector/FixedSizeBinaryVector.java | 30 +++++++++++++-------
 .../java/org/apache/arrow/vector/Float4Vector.java | 30 +++++++++++++-------
 .../java/org/apache/arrow/vector/Float8Vector.java | 30 +++++++++++++-------
 .../java/org/apache/arrow/vector/IntVector.java    | 30 +++++++++++++-------
 .../org/apache/arrow/vector/IntervalDayVector.java | 30 +++++++++++++-------
 .../arrow/vector/IntervalMonthDayNanoVector.java   | 30 +++++++++++++-------
 .../apache/arrow/vector/IntervalYearVector.java    | 30 +++++++++++++-------
 .../apache/arrow/vector/LargeVarBinaryVector.java  | 11 ++------
 .../apache/arrow/vector/LargeVarCharVector.java    | 10 ++-----
 .../org/apache/arrow/vector/SmallIntVector.java    | 30 +++++++++++++-------
 .../org/apache/arrow/vector/TimeMicroVector.java   | 30 +++++++++++++-------
 .../org/apache/arrow/vector/TimeMilliVector.java   | 30 +++++++++++++-------
 .../org/apache/arrow/vector/TimeNanoVector.java    | 30 +++++++++++++-------
 .../org/apache/arrow/vector/TimeSecVector.java     | 30 +++++++++++++-------
 .../arrow/vector/TimeStampMicroTZVector.java       | 28 +++++++++++--------
 .../apache/arrow/vector/TimeStampMicroVector.java  | 28 +++++++++++--------
 .../arrow/vector/TimeStampMilliTZVector.java       | 28 +++++++++++--------
 .../apache/arrow/vector/TimeStampMilliVector.java  | 28 +++++++++++--------
 .../apache/arrow/vector/TimeStampNanoTZVector.java | 28 +++++++++++--------
 .../apache/arrow/vector/TimeStampNanoVector.java   | 28 +++++++++++--------
 .../apache/arrow/vector/TimeStampSecTZVector.java  | 26 +++++++++++-------
 .../apache/arrow/vector/TimeStampSecVector.java    | 28 +++++++++++--------
 .../org/apache/arrow/vector/TinyIntVector.java     | 30 +++++++++++++-------
 .../java/org/apache/arrow/vector/UInt1Vector.java  | 28 ++++++++++++++++---
 .../java/org/apache/arrow/vector/UInt2Vector.java  | 28 ++++++++++++++++---
 .../java/org/apache/arrow/vector/UInt4Vector.java  | 28 ++++++++++++++++---
 .../java/org/apache/arrow/vector/UInt8Vector.java  | 28 ++++++++++++++++---
 .../org/apache/arrow/vector/VarBinaryVector.java   | 11 ++------
 .../org/apache/arrow/vector/VarCharVector.java     | 10 ++-----
 .../arrow/vector/complex/FixedSizeListVector.java  | 10 +++++--
 .../arrow/vector/complex/LargeListVector.java      |  9 ++++--
 .../apache/arrow/vector/complex/ListVector.java    |  9 ++++--
 .../org/apache/arrow/vector/TestBitVector.java     | 10 +++++++
 .../apache/arrow/vector/TestDecimal256Vector.java  | 11 ++++++++
 .../org/apache/arrow/vector/TestDecimalVector.java | 11 ++++++++
 .../apache/arrow/vector/TestDurationVector.java    | 12 ++++++++
 .../arrow/vector/TestFixedSizeBinaryVector.java    | 10 +++++++
 .../arrow/vector/TestIntervalYearVector.java       | 11 ++++++++
 48 files changed, 763 insertions(+), 347 deletions(-)

diff --git a/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java b/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java
index 0c61ad7072..223ae9aa8c 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java
@@ -580,6 +580,14 @@ public abstract class BaseFixedWidthVector extends BaseValueVector
    */
   public abstract TransferPair getTransferPair(String ref, BufferAllocator allocator);
 
+  /**
+   * Construct a transfer pair of this vector and another vector of same type.
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return TransferPair
+   */
+  public abstract TransferPair getTransferPair(Field field, BufferAllocator allocator);
+
   /**
    * Transfer this vector'data to another vector. The memory associated
    * with this vector is transferred to the allocator of target vector
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/BaseValueVector.java b/java/vector/src/main/java/org/apache/arrow/vector/BaseValueVector.java
index 22fe4254ff..679e5d06c0 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/BaseValueVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/BaseValueVector.java
@@ -24,6 +24,7 @@ import org.apache.arrow.memory.ArrowBuf;
 import org.apache.arrow.memory.BufferAllocator;
 import org.apache.arrow.memory.ReferenceManager;
 import org.apache.arrow.util.Preconditions;
+import org.apache.arrow.vector.complex.reader.FieldReader;
 import org.apache.arrow.vector.util.DataSizeRoundingUtil;
 import org.apache.arrow.vector.util.TransferPair;
 import org.apache.arrow.vector.util.ValueVectorUtility;
@@ -50,6 +51,8 @@ public abstract class BaseValueVector implements ValueVector {
 
   protected final BufferAllocator allocator;
 
+  protected volatile FieldReader fieldReader;
+
   protected BaseValueVector(BufferAllocator allocator) {
     this.allocator = Preconditions.checkNotNull(allocator, "allocator cannot be null");
   }
@@ -143,6 +146,35 @@ public abstract class BaseValueVector implements ValueVector {
     return allocator.getRoundingPolicy().getRoundedSize(bufferSize);
   }
 
+  /**
+   * Each vector has a different reader that implements the FieldReader interface. Overridden methods must make
+   * sure to return the correct concrete reader implementation.
+   *
+   * @return Returns a lambda that initializes a reader when called.
+   */
+  protected abstract FieldReader getReaderImpl();
+
+  /**
+   * Default implementation to create a reader for the vector. Depends on the individual vector
+   * class' implementation of {@link #getReaderImpl} to initialize the reader appropriately.
+   *
+   * @return Concrete instance of FieldReader by using double-checked locking.
+   */
+  public FieldReader getReader() {
+    FieldReader reader = fieldReader;
+
+    if (reader != null) {
+      return reader;
+    }
+    synchronized (this) {
+      if (fieldReader == null) {
+        fieldReader = getReaderImpl();
+      }
+
+      return fieldReader;
+    }
+  }
+
   /**
    * Container for primitive vectors (1 for the validity bit-mask and one to hold the values).
    */
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/BigIntVector.java b/java/vector/src/main/java/org/apache/arrow/vector/BigIntVector.java
index c19955b54e..b0052e7e33 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/BigIntVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/BigIntVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class BigIntVector extends BaseFixedWidthVector implements BaseIntVector {
   public static final byte TYPE_WIDTH = 8;
-  private final FieldReader reader;
 
   /**
    * Instantiate a BigIntVector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class BigIntVector extends BaseFixedWidthVector implements BaseIntV
    */
   public BigIntVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new BigIntReaderImpl(BigIntVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new BigIntReaderImpl(BigIntVector.this);
   }
 
   /**
@@ -286,7 +279,7 @@ public final class BigIntVector extends BaseFixedWidthVector implements BaseIntV
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -298,6 +291,19 @@ public final class BigIntVector extends BaseFixedWidthVector implements BaseIntV
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising of this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -331,6 +337,10 @@ public final class BigIntVector extends BaseFixedWidthVector implements BaseIntV
       to = new BigIntVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new BigIntVector(field, allocator);
+    }
+
     public TransferImpl(BigIntVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/BitVector.java b/java/vector/src/main/java/org/apache/arrow/vector/BitVector.java
index 3bcfd983e6..104819147b 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/BitVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/BitVector.java
@@ -46,8 +46,6 @@ public final class BitVector extends BaseFixedWidthVector {
 
   private static final int HASH_CODE_FOR_ONE = 19;
 
-  private final FieldReader reader;
-
   /**
    * Instantiate a BitVector. This doesn't allocate any memory for
    * the data in vector.
@@ -80,17 +78,11 @@ public final class BitVector extends BaseFixedWidthVector {
    */
   public BitVector(Field field, BufferAllocator allocator) {
     super(field, allocator, 0);
-    reader = new BitReaderImpl(BitVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new BitReaderImpl(BitVector.this);
   }
 
   /**
@@ -542,7 +534,7 @@ public final class BitVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref       name of the target vector
@@ -554,6 +546,19 @@ public final class BitVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -572,6 +577,10 @@ public final class BitVector extends BaseFixedWidthVector {
       to = new BitVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new BitVector(field, allocator);
+    }
+
     public TransferImpl(BitVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/DateDayVector.java b/java/vector/src/main/java/org/apache/arrow/vector/DateDayVector.java
index 3e88268450..c99c578605 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/DateDayVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/DateDayVector.java
@@ -38,7 +38,6 @@ import org.apache.arrow.vector.util.TransferPair;
 public final class DateDayVector extends BaseFixedWidthVector {
 
   public static final byte TYPE_WIDTH = 4;
-  private final FieldReader reader;
 
   /**
    * Instantiate a DateDayVector. This doesn't allocate any memory for
@@ -72,17 +71,11 @@ public final class DateDayVector extends BaseFixedWidthVector {
    */
   public DateDayVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new DateDayReaderImpl(DateDayVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new DateDayReaderImpl(DateDayVector.this);
   }
 
   /**
@@ -290,7 +283,7 @@ public final class DateDayVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -302,6 +295,19 @@ public final class DateDayVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -320,6 +326,10 @@ public final class DateDayVector extends BaseFixedWidthVector {
       to = new DateDayVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new DateDayVector(field, allocator);
+    }
+
     public TransferImpl(DateDayVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/DateMilliVector.java b/java/vector/src/main/java/org/apache/arrow/vector/DateMilliVector.java
index 73738d7717..6ab8ac4eed 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/DateMilliVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/DateMilliVector.java
@@ -40,7 +40,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class DateMilliVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 8;
-  private final FieldReader reader;
 
   /**
    * Instantiate a DateMilliVector. This doesn't allocate any memory for
@@ -74,17 +73,11 @@ public final class DateMilliVector extends BaseFixedWidthVector {
    */
   public DateMilliVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new DateMilliReaderImpl(DateMilliVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new DateMilliReaderImpl(DateMilliVector.this);
   }
 
   /**
@@ -293,7 +286,7 @@ public final class DateMilliVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -305,6 +298,19 @@ public final class DateMilliVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -323,6 +329,10 @@ public final class DateMilliVector extends BaseFixedWidthVector {
       to = new DateMilliVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new DateMilliVector(field, allocator);
+    }
+
     public TransferImpl(DateMilliVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java b/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java
index 5a1526b0c4..4ccee50d68 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java
@@ -46,7 +46,6 @@ public final class Decimal256Vector extends BaseFixedWidthVector {
   public static final int MAX_PRECISION = 76;
   public static final byte TYPE_WIDTH = 32;
   private static final boolean LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
-  private final FieldReader reader;
 
   private final int precision;
   private final int scale;
@@ -85,19 +84,13 @@ public final class Decimal256Vector extends BaseFixedWidthVector {
   public Decimal256Vector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
     ArrowType.Decimal arrowType = (ArrowType.Decimal) field.getFieldType().getType();
-    reader = new Decimal256ReaderImpl(Decimal256Vector.this);
     this.precision = arrowType.getPrecision();
     this.scale = arrowType.getScale();
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new Decimal256ReaderImpl(Decimal256Vector.this);
   }
 
   /**
@@ -532,7 +525,7 @@ public final class Decimal256Vector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -544,6 +537,19 @@ public final class Decimal256Vector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -563,6 +569,10 @@ public final class Decimal256Vector extends BaseFixedWidthVector {
               Decimal256Vector.this.scale);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new Decimal256Vector(field, allocator);
+    }
+
     public TransferImpl(Decimal256Vector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java b/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
index 3fa9152a26..db04563df2 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
@@ -45,7 +45,6 @@ public final class DecimalVector extends BaseFixedWidthVector {
   public static final int MAX_PRECISION = 38;
   public static final byte TYPE_WIDTH = 16;
   private static final boolean LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
-  private final FieldReader reader;
 
   private final int precision;
   private final int scale;
@@ -84,19 +83,13 @@ public final class DecimalVector extends BaseFixedWidthVector {
   public DecimalVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
     ArrowType.Decimal arrowType = (ArrowType.Decimal) field.getFieldType().getType();
-    reader = new DecimalReaderImpl(DecimalVector.this);
     this.precision = arrowType.getPrecision();
     this.scale = arrowType.getScale();
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new DecimalReaderImpl(DecimalVector.this);
   }
 
   /**
@@ -531,7 +524,7 @@ public final class DecimalVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -543,6 +536,19 @@ public final class DecimalVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -562,6 +568,10 @@ public final class DecimalVector extends BaseFixedWidthVector {
               DecimalVector.this.scale);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new DecimalVector(field, allocator);
+    }
+
     public TransferImpl(DecimalVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/DurationVector.java b/java/vector/src/main/java/org/apache/arrow/vector/DurationVector.java
index 7af21a8ecd..1e1db0d1c3 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/DurationVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/DurationVector.java
@@ -43,7 +43,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class DurationVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 8;
-  private final FieldReader reader;
 
   private final TimeUnit unit;
 
@@ -68,18 +67,12 @@ public final class DurationVector extends BaseFixedWidthVector {
    */
   public DurationVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new DurationReaderImpl(DurationVector.this);
     this.unit = ((ArrowType.Duration) field.getFieldType().getType()).getUnit();
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new DurationReaderImpl(DurationVector.this);
   }
 
   /**
@@ -369,6 +362,19 @@ public final class DurationVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -387,6 +393,10 @@ public final class DurationVector extends BaseFixedWidthVector {
       to = new DurationVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new DurationVector(field, allocator);
+    }
+
     public TransferImpl(DurationVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/ExtensionTypeVector.java b/java/vector/src/main/java/org/apache/arrow/vector/ExtensionTypeVector.java
index ee5b700f50..9433719c5b 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/ExtensionTypeVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/ExtensionTypeVector.java
@@ -131,7 +131,7 @@ public abstract class ExtensionTypeVector<T extends ValueVector & FieldVector> e
   }
 
   @Override
-  public FieldReader getReader() {
+  protected FieldReader getReaderImpl() {
     return underlyingVector.getReader();
   }
 
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java b/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java
index f9ea37e4c3..3ce2bb77cc 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java
@@ -39,7 +39,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public class FixedSizeBinaryVector extends BaseFixedWidthVector {
   private final int byteWidth;
-  private final FieldReader reader;
 
   /**
    * Instantiate a FixedSizeBinaryVector. This doesn't allocate any memory for
@@ -74,18 +73,12 @@ public class FixedSizeBinaryVector extends BaseFixedWidthVector {
    */
   public FixedSizeBinaryVector(Field field, BufferAllocator allocator) {
     super(field, allocator, ((FixedSizeBinary) field.getFieldType().getType()).getByteWidth());
-    reader = new FixedSizeBinaryReaderImpl(FixedSizeBinaryVector.this);
     byteWidth = ((FixedSizeBinary) field.getFieldType().getType()).getByteWidth();
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new FixedSizeBinaryReaderImpl(FixedSizeBinaryVector.this);
   }
 
   /**
@@ -335,7 +328,7 @@ public class FixedSizeBinaryVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref       name of the target vector
@@ -347,6 +340,19 @@ public class FixedSizeBinaryVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -365,6 +371,10 @@ public class FixedSizeBinaryVector extends BaseFixedWidthVector {
       to = new FixedSizeBinaryVector(ref, allocator, FixedSizeBinaryVector.this.byteWidth);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new FixedSizeBinaryVector(field, allocator);
+    }
+
     public TransferImpl(FixedSizeBinaryVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/Float4Vector.java b/java/vector/src/main/java/org/apache/arrow/vector/Float4Vector.java
index 365a1529bb..4b56a22f2d 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/Float4Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/Float4Vector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class Float4Vector extends BaseFixedWidthVector implements FloatingPointVector {
   public static final byte TYPE_WIDTH = 4;
-  private final FieldReader reader;
 
   /**
    * Instantiate a Float4Vector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class Float4Vector extends BaseFixedWidthVector implements Floating
    */
   public Float4Vector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new Float4ReaderImpl(Float4Vector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new Float4ReaderImpl(Float4Vector.this);
   }
 
   /**
@@ -304,7 +297,7 @@ public final class Float4Vector extends BaseFixedWidthVector implements Floating
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -316,6 +309,19 @@ public final class Float4Vector extends BaseFixedWidthVector implements Floating
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -334,6 +340,10 @@ public final class Float4Vector extends BaseFixedWidthVector implements Floating
       to = new Float4Vector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new Float4Vector(field, allocator);
+    }
+
     public TransferImpl(Float4Vector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/Float8Vector.java b/java/vector/src/main/java/org/apache/arrow/vector/Float8Vector.java
index 948390d46f..7e4fae7087 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/Float8Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/Float8Vector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class Float8Vector extends BaseFixedWidthVector implements FloatingPointVector {
   public static final byte TYPE_WIDTH = 8;
-  private final FieldReader reader;
 
   /**
    * Instantiate a Float8Vector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class Float8Vector extends BaseFixedWidthVector implements Floating
    */
   public Float8Vector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new Float8ReaderImpl(Float8Vector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new Float8ReaderImpl(Float8Vector.this);
   }
 
   /**
@@ -305,7 +298,7 @@ public final class Float8Vector extends BaseFixedWidthVector implements Floating
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -317,6 +310,19 @@ public final class Float8Vector extends BaseFixedWidthVector implements Floating
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -335,6 +341,10 @@ public final class Float8Vector extends BaseFixedWidthVector implements Floating
       to = new Float8Vector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new Float8Vector(field, allocator);
+    }
+
     public TransferImpl(Float8Vector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/IntVector.java b/java/vector/src/main/java/org/apache/arrow/vector/IntVector.java
index e591ec1e85..5c8ef440e8 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/IntVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/IntVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class IntVector extends BaseFixedWidthVector implements BaseIntVector {
   public static final byte TYPE_WIDTH = 4;
-  private final FieldReader reader;
 
   /**
    * Instantiate a IntVector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class IntVector extends BaseFixedWidthVector implements BaseIntVect
    */
   public IntVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new IntReaderImpl(IntVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new IntReaderImpl(IntVector.this);
   }
 
   /**
@@ -290,7 +283,7 @@ public final class IntVector extends BaseFixedWidthVector implements BaseIntVect
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref       name of the target vector
@@ -302,6 +295,19 @@ public final class IntVector extends BaseFixedWidthVector implements BaseIntVect
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -335,6 +341,10 @@ public final class IntVector extends BaseFixedWidthVector implements BaseIntVect
       to = new IntVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new IntVector(field, allocator);
+    }
+
     public TransferImpl(IntVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/IntervalDayVector.java b/java/vector/src/main/java/org/apache/arrow/vector/IntervalDayVector.java
index 0dc860e6b8..35312ba7c9 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/IntervalDayVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/IntervalDayVector.java
@@ -41,7 +41,6 @@ import org.apache.arrow.vector.util.TransferPair;
 public final class IntervalDayVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 8;
   private static final byte MILLISECOND_OFFSET = 4;
-  private final FieldReader reader;
 
   /**
    * Instantiate a IntervalDayVector. This doesn't allocate any memory for
@@ -75,17 +74,11 @@ public final class IntervalDayVector extends BaseFixedWidthVector {
    */
   public IntervalDayVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new IntervalDayReaderImpl(IntervalDayVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new IntervalDayReaderImpl(IntervalDayVector.this);
   }
 
   /**
@@ -376,7 +369,7 @@ public final class IntervalDayVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -388,6 +381,19 @@ public final class IntervalDayVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -406,6 +412,10 @@ public final class IntervalDayVector extends BaseFixedWidthVector {
       to = new IntervalDayVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new IntervalDayVector(field, allocator);
+    }
+
     public TransferImpl(IntervalDayVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/IntervalMonthDayNanoVector.java b/java/vector/src/main/java/org/apache/arrow/vector/IntervalMonthDayNanoVector.java
index 888efbc9aa..73bbc0a2c1 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/IntervalMonthDayNanoVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/IntervalMonthDayNanoVector.java
@@ -46,7 +46,6 @@ public final class IntervalMonthDayNanoVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 16;
   private static final byte DAY_OFFSET = 4;
   private static final byte NANOSECOND_OFFSET = 8;
-  private final FieldReader reader;
 
 
   /**
@@ -81,17 +80,11 @@ public final class IntervalMonthDayNanoVector extends BaseFixedWidthVector {
    */
   public IntervalMonthDayNanoVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new IntervalMonthDayNanoReaderImpl(IntervalMonthDayNanoVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new IntervalMonthDayNanoReaderImpl(IntervalMonthDayNanoVector.this);
   }
 
   /**
@@ -385,7 +378,7 @@ public final class IntervalMonthDayNanoVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -397,6 +390,19 @@ public final class IntervalMonthDayNanoVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising of this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -415,6 +421,10 @@ public final class IntervalMonthDayNanoVector extends BaseFixedWidthVector {
       to = new IntervalMonthDayNanoVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new IntervalMonthDayNanoVector(field, allocator);
+    }
+
     public TransferImpl(IntervalMonthDayNanoVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/IntervalYearVector.java b/java/vector/src/main/java/org/apache/arrow/vector/IntervalYearVector.java
index 7ddfe6b78b..7fe572f3ff 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/IntervalYearVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/IntervalYearVector.java
@@ -39,7 +39,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class IntervalYearVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 4;
-  private final FieldReader reader;
 
   /**
    * Instantiate a IntervalYearVector. This doesn't allocate any memory for
@@ -73,17 +72,11 @@ public final class IntervalYearVector extends BaseFixedWidthVector {
    */
   public IntervalYearVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new IntervalYearReaderImpl(IntervalYearVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new IntervalYearReaderImpl(IntervalYearVector.this);
   }
 
   /**
@@ -325,7 +318,7 @@ public final class IntervalYearVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -337,6 +330,19 @@ public final class IntervalYearVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -355,6 +361,10 @@ public final class IntervalYearVector extends BaseFixedWidthVector {
       to = new IntervalYearVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new IntervalYearVector(field, allocator);
+    }
+
     public TransferImpl(IntervalYearVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/LargeVarBinaryVector.java b/java/vector/src/main/java/org/apache/arrow/vector/LargeVarBinaryVector.java
index e9d60b38e7..0063a61da5 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/LargeVarBinaryVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/LargeVarBinaryVector.java
@@ -34,7 +34,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * The size of the underlying buffer can be over 2GB.
  */
 public final class LargeVarBinaryVector extends BaseLargeVariableWidthVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a LargeVarBinaryVector. This doesn't allocate any memory for
@@ -68,17 +67,11 @@ public final class LargeVarBinaryVector extends BaseLargeVariableWidthVector {
    */
   public LargeVarBinaryVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new LargeVarBinaryReaderImpl(LargeVarBinaryVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new LargeVarBinaryReaderImpl(LargeVarBinaryVector.this);
   }
 
   /**
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java b/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java
index fd20572601..1f8d9b7d3a 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * </p>
  */
 public final class LargeVarCharVector extends BaseLargeVariableWidthVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a LargeVarCharVector. This doesn't allocate any memory for
@@ -69,16 +68,11 @@ public final class LargeVarCharVector extends BaseLargeVariableWidthVector {
    */
   public LargeVarCharVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new LargeVarCharReaderImpl(LargeVarCharVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new LargeVarCharReaderImpl(LargeVarCharVector.this);
   }
 
   /**
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/SmallIntVector.java b/java/vector/src/main/java/org/apache/arrow/vector/SmallIntVector.java
index 1de6dea90f..518ee70739 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/SmallIntVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/SmallIntVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class SmallIntVector extends BaseFixedWidthVector implements BaseIntVector {
   public static final byte TYPE_WIDTH = 2;
-  private final FieldReader reader;
 
   /**
    * Instantiate a SmallIntVector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class SmallIntVector extends BaseFixedWidthVector implements BaseIn
    */
   public SmallIntVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new SmallIntReaderImpl(SmallIntVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new SmallIntReaderImpl(SmallIntVector.this);
   }
 
   /**
@@ -317,7 +310,7 @@ public final class SmallIntVector extends BaseFixedWidthVector implements BaseIn
    *----------------------------------------------------------------*/
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -329,6 +322,19 @@ public final class SmallIntVector extends BaseFixedWidthVector implements BaseIn
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -362,6 +368,10 @@ public final class SmallIntVector extends BaseFixedWidthVector implements BaseIn
       to = new SmallIntVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new SmallIntVector(field, allocator);
+    }
+
     public TransferImpl(SmallIntVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeMicroVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeMicroVector.java
index cf128859e4..86738cd221 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeMicroVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeMicroVector.java
@@ -38,7 +38,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class TimeMicroVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 8;
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeMicroVector. This doesn't allocate any memory for
@@ -72,17 +71,11 @@ public final class TimeMicroVector extends BaseFixedWidthVector {
    */
   public TimeMicroVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new TimeMicroReaderImpl(TimeMicroVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeMicroReaderImpl(TimeMicroVector.this);
   }
 
   /**
@@ -290,7 +283,7 @@ public final class TimeMicroVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -302,6 +295,19 @@ public final class TimeMicroVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -320,6 +326,10 @@ public final class TimeMicroVector extends BaseFixedWidthVector {
       to = new TimeMicroVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new TimeMicroVector(field, allocator);
+    }
+
     public TransferImpl(TimeMicroVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeMilliVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeMilliVector.java
index b96990b106..480add9109 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeMilliVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeMilliVector.java
@@ -40,7 +40,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class TimeMilliVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 4;
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeMilliVector. This doesn't allocate any memory for
@@ -74,17 +73,11 @@ public final class TimeMilliVector extends BaseFixedWidthVector {
    */
   public TimeMilliVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new TimeMilliReaderImpl(TimeMilliVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeMilliReaderImpl(TimeMilliVector.this);
   }
 
   /**
@@ -294,7 +287,7 @@ public final class TimeMilliVector extends BaseFixedWidthVector {
    *----------------------------------------------------------------*/
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -306,6 +299,19 @@ public final class TimeMilliVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -324,6 +330,10 @@ public final class TimeMilliVector extends BaseFixedWidthVector {
       to = new TimeMilliVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new TimeMilliVector(field, allocator);
+    }
+
     public TransferImpl(TimeMilliVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeNanoVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeNanoVector.java
index bc78a02646..82609cdc44 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeNanoVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeNanoVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class TimeNanoVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 8;
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeNanoVector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class TimeNanoVector extends BaseFixedWidthVector {
    */
   public TimeNanoVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new TimeNanoReaderImpl(TimeNanoVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeNanoReaderImpl(TimeNanoVector.this);
   }
 
   /**
@@ -290,7 +283,7 @@ public final class TimeNanoVector extends BaseFixedWidthVector {
    *----------------------------------------------------------------*/
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -302,6 +295,19 @@ public final class TimeNanoVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -320,6 +326,10 @@ public final class TimeNanoVector extends BaseFixedWidthVector {
       to = new TimeNanoVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new TimeNanoVector(field, allocator);
+    }
+
     public TransferImpl(TimeNanoVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeSecVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeSecVector.java
index 29b7381be3..9b7614e55b 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeSecVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeSecVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class TimeSecVector extends BaseFixedWidthVector {
   public static final byte TYPE_WIDTH = 4;
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeSecVector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class TimeSecVector extends BaseFixedWidthVector {
    */
   public TimeSecVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new TimeSecReaderImpl(TimeSecVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeSecReaderImpl(TimeSecVector.this);
   }
 
   /**
@@ -291,7 +284,7 @@ public final class TimeSecVector extends BaseFixedWidthVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -303,6 +296,19 @@ public final class TimeSecVector extends BaseFixedWidthVector {
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising of this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -321,6 +327,10 @@ public final class TimeSecVector extends BaseFixedWidthVector {
       to = new TimeSecVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new TimeSecVector(field, allocator);
+    }
+
     public TransferImpl(TimeSecVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroTZVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroTZVector.java
index e083392ffe..a37b444d1a 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroTZVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroTZVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * (bit vector) is maintained to track which elements in the vector are null.
  */
 public final class TimeStampMicroTZVector extends TimeStampVector {
-  private final FieldReader reader;
   private final String timeZone;
 
   /**
@@ -63,7 +62,6 @@ public final class TimeStampMicroTZVector extends TimeStampVector {
     super(name, fieldType, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) fieldType.getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampMicroTZReaderImpl(TimeStampMicroTZVector.this);
   }
 
   /**
@@ -77,17 +75,11 @@ public final class TimeStampMicroTZVector extends TimeStampVector {
     super(field, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) field.getFieldType().getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampMicroTZReaderImpl(TimeStampMicroTZVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampMicroTZReaderImpl(TimeStampMicroTZVector.this);
   }
 
   /**
@@ -229,7 +221,7 @@ public final class TimeStampMicroTZVector extends TimeStampVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -243,6 +235,20 @@ public final class TimeStampMicroTZVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampMicroTZVector to = new TimeStampMicroTZVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroVector.java
index 5cbef89626..88ce27a187 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMicroVector.java
@@ -38,7 +38,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * (bit vector) is maintained to track which elements in the vector are null.
  */
 public final class TimeStampMicroVector extends TimeStampVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeStampMicroVector. This doesn't allocate any memory for
@@ -61,7 +60,6 @@ public final class TimeStampMicroVector extends TimeStampVector {
    */
   public TimeStampMicroVector(String name, FieldType fieldType, BufferAllocator allocator) {
     super(name, fieldType, allocator);
-    reader = new TimeStampMicroReaderImpl(TimeStampMicroVector.this);
   }
 
   /**
@@ -73,17 +71,11 @@ public final class TimeStampMicroVector extends TimeStampVector {
    */
   public TimeStampMicroVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new TimeStampMicroReaderImpl(TimeStampMicroVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampMicroReaderImpl(TimeStampMicroVector.this);
   }
 
   /**
@@ -209,7 +201,7 @@ public final class TimeStampMicroVector extends TimeStampVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -223,6 +215,20 @@ public final class TimeStampMicroVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampMicroVector to = new TimeStampMicroVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliTZVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliTZVector.java
index d01a43aa1b..775594ceea 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliTZVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliTZVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * (bit vector) is maintained to track which elements in the vector are null.
  */
 public final class TimeStampMilliTZVector extends TimeStampVector {
-  private final FieldReader reader;
   private final String timeZone;
 
   /**
@@ -63,7 +62,6 @@ public final class TimeStampMilliTZVector extends TimeStampVector {
     super(name, fieldType, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) fieldType.getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampMilliTZReaderImpl(TimeStampMilliTZVector.this);
   }
 
   /**
@@ -77,17 +75,11 @@ public final class TimeStampMilliTZVector extends TimeStampVector {
     super(field, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) field.getFieldType().getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampMilliTZReaderImpl(TimeStampMilliTZVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampMilliTZReaderImpl(TimeStampMilliTZVector.this);
   }
 
   /**
@@ -228,7 +220,7 @@ public final class TimeStampMilliTZVector extends TimeStampVector {
    *----------------------------------------------------------------*/
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -242,6 +234,20 @@ public final class TimeStampMilliTZVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampMilliTZVector to = new TimeStampMilliTZVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliVector.java
index 8f46f5606d..a42773269f 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampMilliVector.java
@@ -38,7 +38,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * (bit vector) is maintained to track which elements in the vector are null.
  */
 public final class TimeStampMilliVector extends TimeStampVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeStampMilliVector. This doesn't allocate any memory for
@@ -61,7 +60,6 @@ public final class TimeStampMilliVector extends TimeStampVector {
    */
   public TimeStampMilliVector(String name, FieldType fieldType, BufferAllocator allocator) {
     super(name, fieldType, allocator);
-    reader = new TimeStampMilliReaderImpl(TimeStampMilliVector.this);
   }
 
   /**
@@ -73,17 +71,11 @@ public final class TimeStampMilliVector extends TimeStampVector {
    */
   public TimeStampMilliVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new TimeStampMilliReaderImpl(TimeStampMilliVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampMilliReaderImpl(TimeStampMilliVector.this);
   }
 
   /**
@@ -209,7 +201,7 @@ public final class TimeStampMilliVector extends TimeStampVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -223,6 +215,20 @@ public final class TimeStampMilliVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampMilliVector to = new TimeStampMilliVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoTZVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoTZVector.java
index 2a51babda1..af43cf6fc9 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoTZVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoTZVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * (bit vector) is maintained to track which elements in the vector are null.
  */
 public final class TimeStampNanoTZVector extends TimeStampVector {
-  private final FieldReader reader;
   private final String timeZone;
 
   /**
@@ -63,7 +62,6 @@ public final class TimeStampNanoTZVector extends TimeStampVector {
     super(name, fieldType, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) fieldType.getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampNanoTZReaderImpl(TimeStampNanoTZVector.this);
   }
 
   /**
@@ -77,17 +75,11 @@ public final class TimeStampNanoTZVector extends TimeStampVector {
     super(field, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) field.getFieldType().getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampNanoTZReaderImpl(TimeStampNanoTZVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampNanoTZReaderImpl(TimeStampNanoTZVector.this);
   }
 
   /**
@@ -231,7 +223,7 @@ public final class TimeStampNanoTZVector extends TimeStampVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -245,6 +237,20 @@ public final class TimeStampNanoTZVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampNanoTZVector to = new TimeStampNanoTZVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoVector.java
index 7b87dac437..7b02b1c87d 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampNanoVector.java
@@ -38,7 +38,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * (bit vector) is maintained to track which elements in the vector are null.
  */
 public final class TimeStampNanoVector extends TimeStampVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeStampNanoVector. This doesn't allocate any memory for
@@ -61,7 +60,6 @@ public final class TimeStampNanoVector extends TimeStampVector {
    */
   public TimeStampNanoVector(String name, FieldType fieldType, BufferAllocator allocator) {
     super(name, fieldType, allocator);
-    reader = new TimeStampNanoReaderImpl(TimeStampNanoVector.this);
   }
 
   /**
@@ -73,17 +71,11 @@ public final class TimeStampNanoVector extends TimeStampVector {
    */
   public TimeStampNanoVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new TimeStampNanoReaderImpl(TimeStampNanoVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampNanoReaderImpl(TimeStampNanoVector.this);
   }
 
   /**
@@ -209,7 +201,7 @@ public final class TimeStampNanoVector extends TimeStampVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -223,6 +215,20 @@ public final class TimeStampNanoVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampNanoVector to = new TimeStampNanoVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecTZVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecTZVector.java
index 47e796e995..5837e9d851 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecTZVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecTZVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * (bit vector) is maintained to track which elements in the vector are null.
  */
 public final class TimeStampSecTZVector extends TimeStampVector {
-  private final FieldReader reader;
   private final String timeZone;
 
   /**
@@ -63,7 +62,6 @@ public final class TimeStampSecTZVector extends TimeStampVector {
     super(name, fieldType, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) fieldType.getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampSecTZReaderImpl(TimeStampSecTZVector.this);
   }
 
   /**
@@ -77,17 +75,11 @@ public final class TimeStampSecTZVector extends TimeStampVector {
     super(field, allocator);
     ArrowType.Timestamp arrowType = (ArrowType.Timestamp) field.getFieldType().getType();
     timeZone = arrowType.getTimezone();
-    reader = new TimeStampSecTZReaderImpl(TimeStampSecTZVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampSecTZReaderImpl(TimeStampSecTZVector.this);
   }
 
   /**
@@ -242,6 +234,20 @@ public final class TimeStampSecTZVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising of this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampSecTZVector to = new TimeStampSecTZVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecVector.java
index f12e19684b..1e24914033 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TimeStampSecVector.java
@@ -38,7 +38,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * maintained to track which elements in the vector are null.
  */
 public final class TimeStampSecVector extends TimeStampVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a TimeStampSecVector. This doesn't allocate any memory for
@@ -61,7 +60,6 @@ public final class TimeStampSecVector extends TimeStampVector {
    */
   public TimeStampSecVector(String name, FieldType fieldType, BufferAllocator allocator) {
     super(name, fieldType, allocator);
-    reader = new TimeStampSecReaderImpl(TimeStampSecVector.this);
   }
 
   /**
@@ -73,17 +71,11 @@ public final class TimeStampSecVector extends TimeStampVector {
    */
   public TimeStampSecVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new TimeStampSecReaderImpl(TimeStampSecVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TimeStampSecReaderImpl(TimeStampSecVector.this);
   }
 
   /**
@@ -210,7 +202,7 @@ public final class TimeStampSecVector extends TimeStampVector {
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -224,6 +216,20 @@ public final class TimeStampSecVector extends TimeStampVector {
     return new TransferImpl(to);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    TimeStampSecVector to = new TimeStampSecVector(field, allocator);
+    return new TransferImpl(to);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/TinyIntVector.java b/java/vector/src/main/java/org/apache/arrow/vector/TinyIntVector.java
index f08b0e02f8..4c4eee1342 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/TinyIntVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/TinyIntVector.java
@@ -37,7 +37,6 @@ import org.apache.arrow.vector.util.TransferPair;
  */
 public final class TinyIntVector extends BaseFixedWidthVector implements BaseIntVector {
   public static final byte TYPE_WIDTH = 1;
-  private final FieldReader reader;
 
   /**
    * Instantiate a TinyIntVector. This doesn't allocate any memory for
@@ -71,17 +70,11 @@ public final class TinyIntVector extends BaseFixedWidthVector implements BaseInt
    */
   public TinyIntVector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new TinyIntReaderImpl(TinyIntVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new TinyIntReaderImpl(TinyIntVector.this);
   }
 
   /**
@@ -318,7 +311,7 @@ public final class TinyIntVector extends BaseFixedWidthVector implements BaseInt
 
 
   /**
-   * Construct a TransferPair comprising of this and a target vector of
+   * Construct a TransferPair comprising this and a target vector of
    * the same type.
    *
    * @param ref name of the target vector
@@ -330,6 +323,19 @@ public final class TinyIntVector extends BaseFixedWidthVector implements BaseInt
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   /**
    * Construct a TransferPair with a desired target vector of the same type.
    *
@@ -363,6 +369,10 @@ public final class TinyIntVector extends BaseFixedWidthVector implements BaseInt
       to = new TinyIntVector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new TinyIntVector(field, allocator);
+    }
+
     public TransferImpl(TinyIntVector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/UInt1Vector.java b/java/vector/src/main/java/org/apache/arrow/vector/UInt1Vector.java
index bd9a732c10..777df3fb1e 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/UInt1Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/UInt1Vector.java
@@ -48,7 +48,6 @@ public final class UInt1Vector extends BaseFixedWidthVector implements BaseIntVe
   public static final byte MAX_UINT1 = (byte) 0XFF;
 
   public static final byte TYPE_WIDTH = 1;
-  private final FieldReader reader;
 
   public UInt1Vector(String name, BufferAllocator allocator) {
     this(name, FieldType.nullable(MinorType.UINT1.getType()), allocator);
@@ -58,14 +57,18 @@ public final class UInt1Vector extends BaseFixedWidthVector implements BaseIntVe
     this(new Field(name, fieldType, null), allocator);
   }
 
+  /**
+   * Constructor for UInt1Vector.
+   * @param field Field type
+   * @param allocator Allocator type
+   */
   public UInt1Vector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new UInt1ReaderImpl(UInt1Vector.this);
   }
 
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new UInt1ReaderImpl(UInt1Vector.this);
   }
 
   @Override
@@ -309,6 +312,19 @@ public final class UInt1Vector extends BaseFixedWidthVector implements BaseIntVe
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   @Override
   public TransferPair makeTransferPair(ValueVector to) {
     return new TransferImpl((UInt1Vector) to);
@@ -341,6 +357,10 @@ public final class UInt1Vector extends BaseFixedWidthVector implements BaseIntVe
       to = new UInt1Vector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new UInt1Vector(field, allocator);
+    }
+
     public TransferImpl(UInt1Vector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/UInt2Vector.java b/java/vector/src/main/java/org/apache/arrow/vector/UInt2Vector.java
index 5c29ab6b32..e5b95be191 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/UInt2Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/UInt2Vector.java
@@ -44,7 +44,6 @@ public final class UInt2Vector extends BaseFixedWidthVector implements BaseIntVe
   public static final char MAX_UINT2 = (char) 0XFFFF;
 
   public static final byte TYPE_WIDTH = 2;
-  private final FieldReader reader;
 
   public UInt2Vector(String name, BufferAllocator allocator) {
     this(name, FieldType.nullable(MinorType.UINT2.getType()), allocator);
@@ -54,14 +53,18 @@ public final class UInt2Vector extends BaseFixedWidthVector implements BaseIntVe
     this(new Field(name, fieldType, null), allocator);
   }
 
+  /**
+   * Constructor for UInt2Vector type.
+   * @param field Field type
+   * @param allocator Allocator type
+   */
   public UInt2Vector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new UInt2ReaderImpl(UInt2Vector.this);
   }
 
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new UInt2ReaderImpl(UInt2Vector.this);
   }
 
   @Override
@@ -286,6 +289,19 @@ public final class UInt2Vector extends BaseFixedWidthVector implements BaseIntVe
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   @Override
   public TransferPair makeTransferPair(ValueVector to) {
     return new TransferImpl((UInt2Vector) to);
@@ -319,6 +335,10 @@ public final class UInt2Vector extends BaseFixedWidthVector implements BaseIntVe
       to = new UInt2Vector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new UInt2Vector(field, allocator);
+    }
+
     public TransferImpl(UInt2Vector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/UInt4Vector.java b/java/vector/src/main/java/org/apache/arrow/vector/UInt4Vector.java
index cc954d67dd..bda98b1200 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/UInt4Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/UInt4Vector.java
@@ -49,7 +49,6 @@ public final class UInt4Vector extends BaseFixedWidthVector implements BaseIntVe
   public static final int MAX_UINT4 = 0XFFFFFFFF;
 
   public static final byte TYPE_WIDTH = 4;
-  private final FieldReader reader;
 
   public UInt4Vector(String name, BufferAllocator allocator) {
     this(name, FieldType.nullable(MinorType.UINT4.getType()), allocator);
@@ -59,14 +58,18 @@ public final class UInt4Vector extends BaseFixedWidthVector implements BaseIntVe
     this(new Field(name, fieldType, null), allocator);
   }
 
+  /**
+   * Constructor for UInt4Vector.
+   * @param field Field type
+   * @param allocator Allocator type
+   */
   public UInt4Vector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new UInt4ReaderImpl(UInt4Vector.this);
   }
 
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new UInt4ReaderImpl(UInt4Vector.this);
   }
 
   @Override
@@ -281,6 +284,19 @@ public final class UInt4Vector extends BaseFixedWidthVector implements BaseIntVe
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   @Override
   public TransferPair makeTransferPair(ValueVector to) {
     return new TransferImpl((UInt4Vector) to);
@@ -313,6 +329,10 @@ public final class UInt4Vector extends BaseFixedWidthVector implements BaseIntVe
       to = new UInt4Vector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new UInt4Vector(field, allocator);
+    }
+
     public TransferImpl(UInt4Vector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/UInt8Vector.java b/java/vector/src/main/java/org/apache/arrow/vector/UInt8Vector.java
index 98eaf25a6e..5e7c18902f 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/UInt8Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/UInt8Vector.java
@@ -46,7 +46,6 @@ public final class UInt8Vector extends BaseFixedWidthVector implements BaseIntVe
   public static final long MAX_UINT8 = 0XFFFFFFFFFFFFFFFFL;
 
   public static final byte TYPE_WIDTH = 8;
-  private final FieldReader reader;
 
   public UInt8Vector(String name, BufferAllocator allocator) {
     this(name, FieldType.nullable(MinorType.UINT8.getType()), allocator);
@@ -56,14 +55,18 @@ public final class UInt8Vector extends BaseFixedWidthVector implements BaseIntVe
     this(new Field(name, fieldType, null), allocator);
   }
 
+  /**
+   * Constructor for UInt8Vector.
+   * @param field Field type
+   * @param allocator Allocator type.
+   */
   public UInt8Vector(Field field, BufferAllocator allocator) {
     super(field, allocator, TYPE_WIDTH);
-    reader = new UInt8ReaderImpl(UInt8Vector.this);
   }
 
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new UInt8ReaderImpl(UInt8Vector.this);
   }
 
   @Override
@@ -277,6 +280,19 @@ public final class UInt8Vector extends BaseFixedWidthVector implements BaseIntVe
     return new TransferImpl(ref, allocator);
   }
 
+  /**
+   * Construct a TransferPair comprising this and a target vector of
+   * the same type.
+   *
+   * @param field Field object used by the target vector
+   * @param allocator allocator for the target vector
+   * @return {@link TransferPair}
+   */
+  @Override
+  public TransferPair getTransferPair(Field field, BufferAllocator allocator) {
+    return new TransferImpl(field, allocator);
+  }
+
   @Override
   public TransferPair makeTransferPair(ValueVector to) {
     return new TransferImpl((UInt8Vector) to);
@@ -309,6 +325,10 @@ public final class UInt8Vector extends BaseFixedWidthVector implements BaseIntVe
       to = new UInt8Vector(ref, field.getFieldType(), allocator);
     }
 
+    public TransferImpl(Field field, BufferAllocator allocator) {
+      to = new UInt8Vector(field, allocator);
+    }
+
     public TransferImpl(UInt8Vector to) {
       this.to = to;
     }
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/VarBinaryVector.java b/java/vector/src/main/java/org/apache/arrow/vector/VarBinaryVector.java
index 798d30fe4a..34e072aaa8 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/VarBinaryVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/VarBinaryVector.java
@@ -35,7 +35,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * to track which elements in the vector are null.
  */
 public final class VarBinaryVector extends BaseVariableWidthVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a VarBinaryVector. This doesn't allocate any memory for
@@ -69,17 +68,11 @@ public final class VarBinaryVector extends BaseVariableWidthVector {
    */
   public VarBinaryVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new VarBinaryReaderImpl(VarBinaryVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   *
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new VarBinaryReaderImpl(VarBinaryVector.this);
   }
 
   /**
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java b/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java
index e725e2d283..bc5c68b29f 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java
@@ -36,7 +36,6 @@ import org.apache.arrow.vector.util.TransferPair;
  * to track which elements in the vector are null.
  */
 public final class VarCharVector extends BaseVariableWidthVector {
-  private final FieldReader reader;
 
   /**
    * Instantiate a VarCharVector. This doesn't allocate any memory for
@@ -68,16 +67,11 @@ public final class VarCharVector extends BaseVariableWidthVector {
    */
   public VarCharVector(Field field, BufferAllocator allocator) {
     super(field, allocator);
-    reader = new VarCharReaderImpl(VarCharVector.this);
   }
 
-  /**
-   * Get a reader that supports reading values from this vector.
-   * @return Field Reader for this vector
-   */
   @Override
-  public FieldReader getReader() {
-    return reader;
+  protected FieldReader getReaderImpl() {
+    return new VarCharReaderImpl(VarCharVector.this);
   }
 
   /**
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/complex/FixedSizeListVector.java b/java/vector/src/main/java/org/apache/arrow/vector/complex/FixedSizeListVector.java
index 9b7f6e0306..0f78829181 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/complex/FixedSizeListVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/complex/FixedSizeListVector.java
@@ -48,6 +48,7 @@ import org.apache.arrow.vector.ZeroVector;
 import org.apache.arrow.vector.compare.VectorVisitor;
 import org.apache.arrow.vector.complex.impl.UnionFixedSizeListReader;
 import org.apache.arrow.vector.complex.impl.UnionFixedSizeListWriter;
+import org.apache.arrow.vector.complex.reader.FieldReader;
 import org.apache.arrow.vector.ipc.message.ArrowFieldNode;
 import org.apache.arrow.vector.types.Types.MinorType;
 import org.apache.arrow.vector.types.pojo.ArrowType;
@@ -181,11 +182,14 @@ public class FixedSizeListVector extends BaseValueVector implements BaseListVect
     throw new UnsupportedOperationException("There are no inner vectors. Use getFieldBuffers");
   }
 
+  @Override
+  protected FieldReader getReaderImpl() {
+    return new UnionFixedSizeListReader(this);
+  }
+
   @Override
   public UnionFixedSizeListReader getReader() {
-    if (reader == null) {
-      reader = new UnionFixedSizeListReader(this);
-    }
+    reader = (UnionFixedSizeListReader) super.getReader();
     return reader;
   }
 
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java b/java/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java
index c08c2e496e..6ef5f994fc 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java
@@ -695,11 +695,14 @@ public class LargeListVector extends BaseValueVector implements RepeatedValueVec
     }
   }
 
+  @Override
+  protected FieldReader getReaderImpl() {
+    return new UnionLargeListReader(this);
+  }
+
   @Override
   public UnionLargeListReader getReader() {
-    if (reader == null) {
-      reader = new UnionLargeListReader(this);
-    }
+    reader = (UnionLargeListReader) super.getReader();
     return reader;
   }
 
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/complex/ListVector.java b/java/vector/src/main/java/org/apache/arrow/vector/complex/ListVector.java
index 0fa091fb0c..52e5307e13 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/complex/ListVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/complex/ListVector.java
@@ -566,11 +566,14 @@ public class ListVector extends BaseRepeatedValueVector implements PromotableVec
     }
   }
 
+  @Override
+  protected FieldReader getReaderImpl() {
+    return new UnionListReader(this);
+  }
+
   @Override
   public UnionListReader getReader() {
-    if (reader == null) {
-      reader = new UnionListReader(this);
-    }
+    reader = (UnionListReader) super.getReader();
     return reader;
   }
 
diff --git a/java/vector/src/test/java/org/apache/arrow/vector/TestBitVector.java b/java/vector/src/test/java/org/apache/arrow/vector/TestBitVector.java
index 28d56e342b..075a05c04b 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/TestBitVector.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/TestBitVector.java
@@ -19,6 +19,7 @@ package org.apache.arrow.vector;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import java.util.stream.IntStream;
@@ -540,4 +541,13 @@ public class TestBitVector {
       assertFalse(hashCodes[1] == hashCodes[2]);
     }
   }
+
+  @Test
+  public void testGetTransferPairWithField() {
+    final BitVector fromVector = new BitVector(EMPTY_SCHEMA_PATH, allocator);
+    final TransferPair transferPair = fromVector.getTransferPair(fromVector.getField(), allocator);
+    final BitVector toVector = (BitVector) transferPair.getTo();
+    // Field inside a new vector created by reusing a field should be the same in memory as the original field.
+    assertSame(fromVector.getField(), toVector.getField());
+  }
 }
diff --git a/java/vector/src/test/java/org/apache/arrow/vector/TestDecimal256Vector.java b/java/vector/src/test/java/org/apache/arrow/vector/TestDecimal256Vector.java
index 82c912cef2..51368cf6ae 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/TestDecimal256Vector.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/TestDecimal256Vector.java
@@ -18,6 +18,7 @@
 package org.apache.arrow.vector;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -27,6 +28,7 @@ import java.math.BigInteger;
 import org.apache.arrow.memory.ArrowBuf;
 import org.apache.arrow.memory.BufferAllocator;
 import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.apache.arrow.vector.util.TransferPair;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -337,6 +339,15 @@ public class TestDecimal256Vector {
     }
   }
 
+  @Test
+  public void testGetTransferPairWithField() {
+    final Decimal256Vector fromVector = new Decimal256Vector("decimal", allocator, 10, scale);
+    final TransferPair transferPair = fromVector.getTransferPair(fromVector.getField(), allocator);
+    final Decimal256Vector toVector = (Decimal256Vector) transferPair.getTo();
+    // Field inside a new vector created by reusing a field should be the same in memory as the original field.
+    assertSame(fromVector.getField(), toVector.getField());
+  }
+
   private void verifyWritingArrowBufWithBigEndianBytes(Decimal256Vector decimalVector,
                                                        ArrowBuf buf, BigDecimal[] expectedValues,
                                                        int length) {
diff --git a/java/vector/src/test/java/org/apache/arrow/vector/TestDecimalVector.java b/java/vector/src/test/java/org/apache/arrow/vector/TestDecimalVector.java
index c7e3e436e4..ba25cbe8b5 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/TestDecimalVector.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/TestDecimalVector.java
@@ -18,6 +18,7 @@
 package org.apache.arrow.vector;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -27,6 +28,7 @@ import java.math.BigInteger;
 import org.apache.arrow.memory.ArrowBuf;
 import org.apache.arrow.memory.BufferAllocator;
 import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.apache.arrow.vector.util.TransferPair;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -345,6 +347,15 @@ public class TestDecimalVector {
     }
   }
 
+  @Test
+  public void testGetTransferPairWithField() {
+    final DecimalVector fromVector = new DecimalVector("decimal", allocator, 10, scale);
+    final TransferPair transferPair = fromVector.getTransferPair(fromVector.getField(), allocator);
+    final DecimalVector toVector = (DecimalVector) transferPair.getTo();
+    // Field inside a new vector created by reusing a field should be the same in memory as the original field.
+    assertSame(fromVector.getField(), toVector.getField());
+  }
+
   private void verifyWritingArrowBufWithBigEndianBytes(DecimalVector decimalVector,
                                                        ArrowBuf buf, BigDecimal[] expectedValues,
                                                        int length) {
diff --git a/java/vector/src/test/java/org/apache/arrow/vector/TestDurationVector.java b/java/vector/src/test/java/org/apache/arrow/vector/TestDurationVector.java
index 8ae876f201..c5d4d296cc 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/TestDurationVector.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/TestDurationVector.java
@@ -19,6 +19,7 @@ package org.apache.arrow.vector;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 
 import java.time.Duration;
 
@@ -26,6 +27,7 @@ import org.apache.arrow.memory.RootAllocator;
 import org.apache.arrow.vector.holders.NullableDurationHolder;
 import org.apache.arrow.vector.types.TimeUnit;
 import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.apache.arrow.vector.util.TransferPair;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -134,4 +136,14 @@ public class TestDurationVector {
       assertEquals(1000000 , holder.value);
     }
   }
+
+  @Test
+  public void testGetTransferPairWithField() {
+    final DurationVector fromVector = TestUtils.newVector(DurationVector.class, "nanos",
+        new ArrowType.Duration(TimeUnit.NANOSECOND), allocator);
+    final TransferPair transferPair = fromVector.getTransferPair(fromVector.getField(), allocator);
+    final DurationVector toVector = (DurationVector) transferPair.getTo();
+    // Field inside a new vector created by reusing a field should be the same in memory as the original field.
+    assertSame(fromVector.getField(), toVector.getField());
+  }
 }
diff --git a/java/vector/src/test/java/org/apache/arrow/vector/TestFixedSizeBinaryVector.java b/java/vector/src/test/java/org/apache/arrow/vector/TestFixedSizeBinaryVector.java
index e8f764a21e..c413f4e23e 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/TestFixedSizeBinaryVector.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/TestFixedSizeBinaryVector.java
@@ -24,6 +24,7 @@ import org.apache.arrow.memory.ArrowBuf;
 import org.apache.arrow.memory.BufferAllocator;
 import org.apache.arrow.vector.holders.FixedSizeBinaryHolder;
 import org.apache.arrow.vector.holders.NullableFixedSizeBinaryHolder;
+import org.apache.arrow.vector.util.TransferPair;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -276,4 +277,13 @@ public class TestFixedSizeBinaryVector {
     vector.setNull(0);
     assertNull(vector.get(0));
   }
+
+  @Test
+  public void testGetTransferPairWithField() {
+    final FixedSizeBinaryVector fromVector = new FixedSizeBinaryVector("fixedSizeBinary", allocator, typeWidth);
+    final TransferPair transferPair = fromVector.getTransferPair(fromVector.getField(), allocator);
+    final FixedSizeBinaryVector toVector = (FixedSizeBinaryVector) transferPair.getTo();
+    // Field inside a new vector created by reusing a field should be the same in memory as the original field.
+    assertSame(fromVector.getField(), toVector.getField());
+  }
 }
diff --git a/java/vector/src/test/java/org/apache/arrow/vector/TestIntervalYearVector.java b/java/vector/src/test/java/org/apache/arrow/vector/TestIntervalYearVector.java
index 9fc15654b3..4b2ae2eb3d 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/TestIntervalYearVector.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/TestIntervalYearVector.java
@@ -18,11 +18,13 @@
 package org.apache.arrow.vector;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 
 import org.apache.arrow.memory.BufferAllocator;
 import org.apache.arrow.vector.types.IntervalUnit;
 import org.apache.arrow.vector.types.Types;
 import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.apache.arrow.vector.util.TransferPair;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -63,4 +65,13 @@ public class TestIntervalYearVector {
       assertEquals(IntervalUnit.YEAR_MONTH, intervalType.getUnit());
     }
   }
+
+  @Test
+  public void testGetTransferPairWithField() {
+    final IntervalYearVector fromVector = new IntervalYearVector("", allocator);
+    final TransferPair transferPair = fromVector.getTransferPair(fromVector.getField(), allocator);
+    final IntervalYearVector toVector = (IntervalYearVector) transferPair.getTo();
+    // Field inside a new vector created by reusing a field should be the same in memory as the original field.
+    assertSame(fromVector.getField(), toVector.getField());
+  }
 }